﻿'// ========================================================================= '
'// ------------------------------------------------------------------------- '
'//!				\file		CM_3DPoints.vb
'			        \date		june 2010
'			        \author		TNick
'
'			        \brief		
'
'
'   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'   This file is considered universal knowledge. No restrictions
'   are imposed; use as you see fit.
'   Please read ReadMe.txt and Licence.txt in root folder
'   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'
'   
'   Edit functionality is to be tested / debugged
'
'// ------------------------------------------------------------------------- '
'// ========================================================================= '
'//
'//
'//
'//
'//  IMPORTS     ------------------------------------------------------------ '
#Region "Imports"

Imports System
Imports Microsoft.Win32

Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.Customization
Imports FSK_XL
Imports Autodesk.AutoCAD.Colors

'Imports Autodesk.AutoCAD.Colors
'Imports Autodesk.AutoCAD.GraphicsSystem

#End Region
'//  IMPORTS     ============================================================ '
'//
'//
'//
'//
'//  DEFINITIONS    --------------------------------------------------------- '
<Assembly: CommandClass(GetType(CM_3DPoints))> 


#Region "Public Structures"


'// --------------------------------------------------------------------- '
'// identifies various parts of a 3D point
Public Enum PT3PART
    NAME = 0    '// Name or number
    NORTH       '// This is Y on Autocad
    EAST        '// This is X on Autocad
    HEIGHT      '// This is Z on Autocad
    DESCR       '// Optional; description

    COUNT       '// For validation check, limits, ...
End Enum
'// ===================================================================== '

'// --------------------------------------------------------------------- '
'// defines the settings for 3D points
Public Structure PT3DSTG
    Dim DecSep As String '// decimal separator character (usually a . or ,)
    Dim FSep() As String '// list of field separators
    Dim FOrd() As PT3PART '// the order of fields in file
    Dim LastImpFile As String
    Dim LastExpFile As String

    Dim lyMark As String  '// name of layer for marker
    Dim lyNr As String    '// name of layer for number / name
    Dim lyZ As String     '// name of layer for height
    Dim lyCode As String  '// name of layer for code / description

    Dim doBlock As Boolean  '// create blocks for each point
    Dim sBlockName As String '// the name of block to insert

    Dim txH As Double      '// height of generated text
    Dim sTxSty As String '// the name of the text style

    '// If a line is found improper, it is ignored
    '// and the process is not breaked
    Dim bIgnErr As Boolean

    '// durring edit, reset the position of attributes
    '// 0 - no reset
    '// 1 - reset
    '// 2 - only moved
    '// 3 - smart
    Dim iRstPos As Integer


    '// on polylick: height from polyline
    Dim bHFromPoly As Boolean
    '// on polylick: use point numbers
    Dim bUsePtNr As Boolean
    '// on polylick: allow non-unique names
    Dim bAllowNonUniq As Boolean
    '// number / name of next point
    Dim sNameSave As String
    '// saved height
    Dim dSaveZ As Double

    '// the format of the coordinates
    Dim sFormCoord As String

End Structure
'// ===================================================================== '

#End Region

Public Delegate Function Del_ImpPt( _
        ByRef acDoc As Document, _
        ByRef pt As FSK_PT3D, _
        ByRef lcStg As PT3DSTG) As Boolean
'//  DEFINITIONS    ========================================================= '
'//
'//
'//
'//
'//  DATA    ---------------------------------------------------------------- '


'//  DATA    ================================================================ '
'//
'//
'//
'//
'//  CLASS    --------------------------------------------------------------- '
Public Class CM_3DPoints
    Inherits CModule

    '// --------------------------------------------------------------------- '
    '// DATA

#Region "Public Constants"
    '// name as displayed in various places
    Public Const sAPPNAME As String = "3D Points"
    '// version as displayed in various places
    Public Const sAPPVER As String = "1.0.0.0"
    '// short description
    Public sAPPTIP As String

    '// Command. Brings up the settings dialog
    Public Const sCMD_SETTINGS As String = "TNIK_3DP_STG"
    '// Command. Brings up the import dialog
    Public Const sCMD_IMPORT As String = "TNIK_3DP_IMP"
    '// Command. Brings up the export dialog
    Public Const sCMD_EXPORT As String = "TNIK_3DP_EXP"
    '// Command. Explodes the selection or all blocks
    Public Const sCMD_EXPLODE As String = "TNIK_3DP_EPLD"
    '// Command. Edits the selection or all blocks
    Public Const sCMD_EDIT As String = "TNIK_3DP_EDIT"
    '// Command. Gets the coordinates of polyline points
    Public Const sCMD_POLYPT As String = "TNIK_3DP_POLY"
    '// Command. Compute the lenght between two points
    Public Const sCMD_DIST As String = "TNIK_3DP_DIST"
    '// Command. Place intermediate points between two points
    Public Const sCMD_INTERM As String = "TNIK_3DP_SPAN"


    '// Attribute name for NAME field
    Public Const sPTOA_NAME As String = "PTNAME"
    '// Attribute name for Z field
    Public Const sPTOA_Z As String = "Z"
    '// Attribute name for description field
    Public Const sPTOA_CODE As String = "CODE"

    '// target for export is clipboard
    Public Const sCLIPB As String = "CLIPBOARD"
#End Region

    '// this is where the settings are stored durring run-time
    Public Shared Stgs As PT3DSTG

    Const EXP_TXT As Integer = 0
    Const EXP_XL As Integer = 1
    Const EXP_CLPB As Integer = 2
    '// ===================================================================== '

#Region "Public specific Functions"

    '// --------------------------------------------------------------------- '
    '// Creates a new block reference to act as a point
    Public Shared Function BlockPoint( _
        ByRef acDoc As Document, _
        ByRef pt As FSK_PT3D, _
        ByRef lcStg As PT3DSTG) As Boolean

        Dim bRet As Boolean = False
        Dim db As Database = acDoc.Database
        Dim ed As Editor = acDoc.Editor

        Dim sForm As String
        If (String.IsNullOrEmpty(CM_3DPoints.Stgs.sFormCoord)) Then
            sForm = "0.000"
        Else
            sForm = CM_3DPoints.Stgs.sFormCoord
        End If

        Using acTrans As Transaction = _
            db.TransactionManager.StartTransaction()
            Try
                '// get a reference to table of blocks
                Dim acBlkTbl As BlockTable = DirectCast( _
                 acTrans.GetObject(db.BlockTableId, OpenMode.ForRead),  _
                 BlockTable)

                Call EnshureLayers(acDoc, acTrans, lcStg)

                If (acBlkTbl.Has(lcStg.sBlockName) = False) Then
                    if CreatePtBlock(lcStg,acDoc) = False Then
                        Exit Try
                    End If
                End If

                ' Get Model space (is just a block)
                Dim acBlkModel As BlockTableRecord = DirectCast( _
                    acTrans.GetObject( _
                        acBlkTbl(BlockTableRecord.ModelSpace), _
                        OpenMode.ForWrite),  _
                    BlockTableRecord)

                '// Get the type of the object
                Dim id_B As ObjectId = acBlkTbl(lcStg.sBlockName)
                ' Create a block reference
                Dim br As BlockReference = _
                    New BlockReference( _
                        New Point3d(pt.East, pt.North, pt.Height), _
                        id_B)
                br.SetDatabaseDefaults()
                ' Add the block reference to Model space
                acBlkModel.AppendEntity(br)
                acTrans.AddNewlyCreatedDBObject(br, True)

                ' open the template block
                Dim Block As BlockTableRecord = DirectCast( _
                    br.BlockTableRecord.GetObject(OpenMode.ForRead),  _
                    BlockTableRecord)

                If Block.HasAttributeDefinitions = False Or _
                    (Block.Database Is Nothing) Then
                    CMain.AlertUser(CMain._T(TX.ERR_WRONGBLK))
                    Exit Try
                End If

                '// Iterate in attributes
                For Each Id As ObjectId In Block
                    Dim Ent As Entity = DirectCast( _
                        Id.GetObject(Autodesk.AutoCAD.DatabaseServices. _
                                     OpenMode.ForRead),  _
                        Entity)

                    '// actual entity
                    If TypeOf Ent Is AttributeDefinition Then
                        Dim AttDef As AttributeDefinition = _
                            DirectCast(Ent, AttributeDefinition)
                        Dim AttRef As New AttributeReference
                        AttRef.SetPropertiesFrom(AttDef)
                        AttRef.SetAttributeFromBlock(AttDef, br.BlockTransform)
                        Select Case AttRef.Tag.ToUpper
                            Case sPTOA_NAME
                                If String.IsNullOrEmpty(pt.Name) = False Then
                                    AttRef.TextString = pt.Name
                                End If
                                AttRef.Layer = lcStg.lyNr
                            Case sPTOA_Z
                                AttRef.TextString = pt.Height.ToString(sForm)
                                AttRef.Layer = lcStg.lyZ
                            Case sPTOA_CODE
                                If String.IsNullOrEmpty(pt.Descr) = False Then
                                    AttRef.TextString = pt.Descr
                                End If
                                AttRef.Layer = lcStg.lyCode
                        End Select
                        '// add this to the drawing
                        br.AttributeCollection.AppendAttribute(AttRef)
                        acTrans.AddNewlyCreatedDBObject(AttRef, True)
                    End If
                Next
                acTrans.Commit()
                bRet = True
            Catch ex As System.Exception
                acTrans.Abort()
                CMain.DebugException(ex)
            End Try
        End Using
        GC.Collect()
        GC.WaitForPendingFinalizers()
        Return bRet
    End Function
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    '// Creates a new group of entities to act as a point
    Public Shared Function EntityPoint( _
        ByRef acDoc As Document, _
        ByRef pt As FSK_PT3D, _
        ByRef lcStg As PT3DSTG) As Boolean

        Dim bRet As Boolean = False
        Dim db As Database = acDoc.Database
        Dim ed As Editor = acDoc.Editor
        Dim Pct As New Point3d(pt.East, pt.North, pt.Height)

        Using acTrans As Transaction = _
            db.TransactionManager.StartTransaction()
            Try
                '// Suplemental space between attributes
                Dim dSupl As Double = lcStg.txH / 6

                call EnshureLayers(acDoc, acTrans, lcStg)

                '// text style to use
                Dim oidTxSty As ObjectId
                Dim acTxStyTbl As TextStyleTable = DirectCast( _
                    acTrans.GetObject(db.TextStyleTableId, OpenMode.ForRead),  _
                    TextStyleTable)
                If (acTxStyTbl.Has(lcStg.sTxSty)) Then
                    oidTxSty = acTxStyTbl(lcStg.sTxSty)
                    If oidTxSty.IsValid = False Then
                        oidTxSty = acTxStyTbl("Standard")
                    End If
                Else
                    Debug.Print("Text style missing from file. Defaulting to Standard")
                    oidTxSty = acTxStyTbl("Standard")
                End If

                '// get a reference to table of blocks
                Dim acBlkTbl As BlockTable = DirectCast( _
                        acTrans.GetObject(db.BlockTableId, _
                                          OpenMode.ForRead),  _
                    BlockTable)

                ' Get Model space (is just a block)
                Dim acBlkModel As BlockTableRecord = DirectCast( _
                        acTrans.GetObject( _
                        acBlkTbl(BlockTableRecord.ModelSpace), _
                        OpenMode.ForWrite),  _
                    BlockTableRecord)


                ' Step 1: Create a circle entity - the marker
                Dim acCirc As Circle = New Circle
                acCirc.SetDatabaseDefaults()
                acCirc.Center = Pct
                acCirc.Layer = lcStg.lyMark
                acCirc.Radius = lcStg.txH / 3
                acBlkModel.AppendEntity(acCirc)
                acTrans.AddNewlyCreatedDBObject(acCirc, True)

                ' Step 2: Create a point entity - the marker
                Dim acPt As DBPoint = New DBPoint
                acPt.SetDatabaseDefaults()
                acPt.Position = Pct
                acPt.Layer = lcStg.lyMark
                acBlkModel.AppendEntity(acPt)
                acTrans.AddNewlyCreatedDBObject(acPt, True)

                ' Step 3: Create attributes
                Dim dXAl As Double = Pct.X + lcStg.txH * (5 / 8)
                Dim acText As DBText

                '   3.1 Name
                If pt.Name.Trim <> "" Then
                    acText = New DBText()
                    acText.SetDatabaseDefaults()
                    acText.TextString = pt.Name
                    acText.Position = New Point3d(dXAl, Pct.Y + lcStg.txH / 2 + dSupl, 0)
                    acText.Layer = lcStg.lyNr
                    acText.TextStyle = oidTxSty
                    acBlkModel.AppendEntity(acText)
                    acTrans.AddNewlyCreatedDBObject(acText, True)
                End If

                '   3.2 Z - Height
                acText = New DBText()
                acText.SetDatabaseDefaults()
                acText.TextString = Pct.Z.ToString("0.000")
                acText.Position = New Point3d(dXAl, Pct.Y - lcStg.txH / 2, 0)
                acText.Layer = lcStg.lyZ
                acText.TextStyle = oidTxSty
                acBlkModel.AppendEntity(acText)
                acTrans.AddNewlyCreatedDBObject(acText, True)

                '   3.3 Code - Description
                If pt.Descr.Trim <> "" Then
                    acText = New DBText()
                    acText.SetDatabaseDefaults()
                    acText.TextString = pt.Descr
                    acText.Position = New Point3d(dXAl, Pct.Y - (3 * lcStg.txH / 2 + dSupl), 0)
                    acText.Layer = lcStg.lyCode
                    acText.TextStyle = oidTxSty
                    acBlkModel.AppendEntity(acText)
                    acTrans.AddNewlyCreatedDBObject(acText, True)
                End If

                acTrans.Commit()
                bRet = True
            Catch ex As System.Exception
                acTrans.Abort()
                CMain.DebugException(ex)
            End Try
        End Using
        GC.Collect()
        GC.WaitForPendingFinalizers()
        Return bRet
    End Function
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    '// Creates the proper block definition in specified drawing
    Public Shared Function CreatePtBlock( _
      ByRef lcStg As PT3DSTG, _
      ByRef acDoc As Document) _
      As Boolean

        Dim db As Database = acDoc.Database
        Dim ed As Editor = acDoc.Editor
        Dim acBlkTbl As BlockTable
        Dim acBlkNewBlock As BlockTableRecord
        Dim bRes As Boolean = False

        Using acTrans As Transaction = _
            db.TransactionManager.StartTransaction()
            Try
                call EnshureLayers(acDoc, acTrans, lcStg)

                acBlkTbl = DirectCast( _
                    acTrans.GetObject(db.BlockTableId, OpenMode.ForWrite),  _
                    BlockTable)
                If (acBlkTbl.Has(lcStg.sBlockName) = False) Then

                    Dim oidTxSty As ObjectId
                    '// Get the text style that we're going to use
                    Dim acTxStyTbl As TextStyleTable = DirectCast( _
                        acTrans.GetObject(db.TextStyleTableId, OpenMode.ForRead),  _
                        TextStyleTable)
                    If (acTxStyTbl.Has(lcStg.sTxSty)) Then
                        oidTxSty = acTxStyTbl(lcStg.sTxSty)
                        If oidTxSty.IsValid = False Then
                            oidTxSty = acTxStyTbl("Standard")
                        End If
                    Else
                        Debug.Print("Text style missing from file. Defaulting to Standard")
                        oidTxSty = acTxStyTbl("Standard")
                    End If
                    '// Create a new (basic, empty) block
                    acBlkNewBlock = New BlockTableRecord()


                    ' Step 1: Set the block name and base point of the 
                    ' block definition.
                    If lcStg.sBlockName = Nothing Or lcStg.sBlockName = "" Then
                        lcStg.sBlockName = "PctV1"
                    End If
                    acBlkNewBlock.Name = lcStg.sBlockName
                    acBlkNewBlock.Origin = New Point3d(0, 0, 0)


                    ' Step 2: Add the block table record to block table.
                    acBlkTbl.Add(acBlkNewBlock)
                    acTrans.AddNewlyCreatedDBObject(acBlkNewBlock, True)
                    ' Open the block table for write.
                    acBlkNewBlock.UpgradeOpen()


                    ' Step 3: Create a circle entity - the marker
                    Dim acCirc As Circle = New Circle
                    acCirc.SetDatabaseDefaults()
                    acCirc.Center = New Point3d(0, 0, 0)
                    acCirc.Layer = lcStg.lyMark
                    acCirc.Radius = lcStg.txH / 3
                    acBlkNewBlock.AppendEntity(acCirc)
                    acTrans.AddNewlyCreatedDBObject(acCirc, True)


                    ' Step 4: Create a point entity - the marker
                    Dim acPt As DBPoint = New DBPoint
                    acPt.SetDatabaseDefaults()
                    acPt.Position = New Point3d(0, 0, 0)
                    acPt.Layer = lcStg.lyMark
                    acBlkNewBlock.AppendEntity(acPt)
                    acTrans.AddNewlyCreatedDBObject(acPt, True)

                    ' Step 5: Create attributes
                    Dim dXAl As Double = lcStg.txH * (5 / 8)
                    Dim acAtr As AttributeDefinition
                    '// Suplemental space between attributes
                    Dim dSupl As Double = lcStg.txH / 6

                    '   5.1 Name
                    acAtr = New AttributeDefinition()
                    acAtr.SetDatabaseDefaults()
                    acAtr.Prompt = CMain._T(TX.NAME)
                    acAtr.TextString = "?"
                    acAtr.Tag = sPTOA_NAME
                    acAtr.Invisible = False
                    acAtr.Verifiable = False
                    acAtr.Preset = False
                    acAtr.Constant = False
                    acAtr.Position = New Point3d(dXAl, lcStg.txH / 2 + dSupl, 0)
                    acAtr.Layer = lcStg.lyNr
                    acAtr.TextStyle = oidTxSty
                    acBlkNewBlock.AppendEntity(acAtr)
                    acTrans.AddNewlyCreatedDBObject(acAtr, True)

                    '   5.2 Z - Height
                    acAtr = New AttributeDefinition()
                    acAtr.SetDatabaseDefaults()
                    acAtr.Prompt = "Z"
                    acAtr.TextString = "0.000"
                    acAtr.Tag = sPTOA_Z
                    acAtr.Invisible = False
                    acAtr.Verifiable = False
                    acAtr.Preset = False
                    acAtr.Constant = False
                    acAtr.Position = New Point3d(dXAl, -lcStg.txH / 2, 0)
                    acAtr.Layer = lcStg.lyZ
                    acAtr.TextStyle = oidTxSty
                    acBlkNewBlock.AppendEntity(acAtr)
                    acTrans.AddNewlyCreatedDBObject(acAtr, True)

                    '   5.3 Code - Description
                    acAtr = New AttributeDefinition()
                    acAtr.SetDatabaseDefaults()
                    acAtr.Prompt = CMain._T(TX.CODE)
                    acAtr.TextString = ""
                    acAtr.Tag = sPTOA_CODE
                    acAtr.Invisible = False
                    acAtr.Verifiable = False
                    acAtr.Preset = False
                    acAtr.Constant = False
                    acAtr.Position = New Point3d(dXAl, -(3 * lcStg.txH / 2 + dSupl), 0)
                    acAtr.Layer = lcStg.lyCode
                    acAtr.TextStyle = oidTxSty
                    acBlkNewBlock.AppendEntity(acAtr)
                    acTrans.AddNewlyCreatedDBObject(acAtr, True)


                    acTrans.Commit()
                    bRes = True
                Else
                    Debug.Print("CreatePtBlock called for a block tht already exists")
                    bRes = True
                End If

            Catch ex As System.Exception
                CMain.DebugException(ex)
                acTrans.Abort()
            Finally

            End Try
            GC.Collect()
            GC.WaitForPendingFinalizers()
        End Using

        Return bRes
    End Function
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    Private Shared Function EnshureLayers( _
        ByRef acDoc As Document, _
        ByRef acTrans As Transaction, _
        ByRef lcStg As PT3DSTG) _
        as Boolean

        Dim bRet As Boolean = False
        Try
            '// see if this drawing has required layers
            '// get a reference to table of blocks
            Dim acLy As LayerTableRecord = Nothing
            Dim acLyTbl As LayerTable = DirectCast( _
             acTrans.GetObject(acDoc.Database.LayerTableId, OpenMode.ForWrite),  _
             LayerTable)
            Dim acCol As new Autodesk.AutoCAD.Colors.Color()

            If (acLyTbl.Has(lcStg.lyCode) = False) Then
                acLy = New LayerTableRecord()
                acLy.Name = lcStg.lyCode
                acLy.Color = Color.FromColorIndex(ColorMethod.ByAci, 41)
                acLyTbl.Add(acLy)
                acTrans.AddNewlyCreatedDBObject(acLy, True)
            End If

            If (acLyTbl.Has(lcStg.lyMark) = False) Then
                acLy = New LayerTableRecord()
                acLy.Name = lcStg.lyMark
                acLy.Color = Color.FromColorIndex(ColorMethod.ByAci, 151)
                acLyTbl.Add(acLy)
                acTrans.AddNewlyCreatedDBObject(acLy, True)
            End If

            If (acLyTbl.Has(lcStg.lyNr) = False) Then
                acLy = New LayerTableRecord()
                acLy.Name = lcStg.lyNr
                acLy.Color = Color.FromColorIndex(ColorMethod.ByAci, 83)
                acLyTbl.Add(acLy)
                acTrans.AddNewlyCreatedDBObject(acLy, True)
            End If

            If (acLyTbl.Has(lcStg.lyZ) = False) Then
                acLy = New LayerTableRecord()
                acLy.Name = lcStg.lyZ
                acLy.Color = Color.FromColorIndex(ColorMethod.ByAci, 52)
                acLyTbl.Add(acLy)
                acTrans.AddNewlyCreatedDBObject(acLy, True)
            End If

            bRet = True
        Catch ex As System.Exception
            CMain.DebugException(ex)
        End Try
        GC.Collect()
        GC.WaitForPendingFinalizers()
        Return bRet
    End Function
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    '// Edit some blocks
    Public Shared Sub EditBlocks(ByRef acDoc As Document, ByRef lcStg As PT3DSTG)
        Try
            If (acDoc Is Nothing) Then
                Return
            End If

            Dim db As Database = acDoc.Database
            Dim ed As Editor = acDoc.Editor
            ed = acDoc.Editor

            Using acTrans As Transaction = _
                db.TransactionManager.StartTransaction()
                Try
                    '// text style to use
                    Dim oidTxSty As ObjectId
                    Dim acTxStyTbl As TextStyleTable = DirectCast( _
                        acTrans.GetObject(db.TextStyleTableId, OpenMode.ForRead),  _
                        TextStyleTable)
                    If (acTxStyTbl.Has(lcStg.sTxSty)) Then
                        oidTxSty = acTxStyTbl(lcStg.sTxSty)
                        If oidTxSty.IsValid = False Then
                            oidTxSty = acTxStyTbl("Standard")
                        End If
                    Else
                        Debug.Print("Text style missing from file. Defaulting to Standard")
                        oidTxSty = acTxStyTbl("Standard")
                    End If

                    call EnshureLayers(acDoc, acTrans, lcStg)

                    '// get a reference to table of blocks
                    Dim acBlkTbl As BlockTable = DirectCast( _
                     acTrans.GetObject(db.BlockTableId, OpenMode.ForRead),  _
                     BlockTable)

                    '// Get Model space (is just a block)
                    Dim acBlkModel As BlockTableRecord = DirectCast( _
                        acTrans.GetObject( _
                            acBlkTbl(BlockTableRecord.ModelSpace), _
                            OpenMode.ForWrite),  _
                        BlockTableRecord)

                    '// see if our block is inside
                    If (acBlkTbl.Has(lcStg.sBlockName) = False) Then
                        CMain.AlertUser(String.Format(CMain._T(TX.PT3D_EBLK), lcStg.sBlockName))
                        Exit Try
                    End If
                    Dim oidTargBlk As ObjectId = acBlkTbl(lcStg.sBlockName)
                    Dim iT As Integer = 0


                    Dim acBlkBlock As BlockTableRecord = _
                        CType(acTrans.GetObject(oidTargBlk, OpenMode.ForWrite),  _
                        BlockTableRecord)
                    '// Loop in entities that compose the block
                    For Each idBlkd As ObjectId In acBlkBlock
                        Dim Ent As DBObject = _
                            acTrans.GetObject(idBlkd, OpenMode.ForRead)
                        If TypeOf Ent Is Circle Then
                            ' "cast" the entity into a circle
                            Dim acCirc As Circle = DirectCast(Ent, Circle)
                            acCirc.UpgradeOpen()
                            acCirc.Radius = lcStg.txH / 3
                            acCirc = Nothing
                        End If
                    Next

                    '' Get the PickFirst selection set
                    Dim acSSPrompt As PromptSelectionResult = ed.SelectImplied()
                    '' If the prompt status is OK, objects were selected before
                    '' the command was started
                    If acSSPrompt.Status = PromptStatus.OK Then
                        Dim acSSet As SelectionSet = acSSPrompt.Value
                        For Each sobj As SelectedObject In acSSet

                            If (Edit_Entity(acDoc, acTrans, acBlkModel, oidTxSty, oidTargBlk, sobj.ObjectId, lcStg)) Then
                                iT = iT + 1
                            End If
                        Next
                        If iT = 0 Then
                            CMain.InformUser(TX.PT3D_NPT)
                            GoTo DoAllBlocks
                        End If
                    Else
DoAllBlocks:
                        For Each idBlkd As ObjectId In acBlkModel
                            If (Edit_Entity(acDoc, acTrans, acBlkModel, oidTxSty, oidTargBlk, idBlkd, lcStg)) Then
                                iT = iT + 1
                            End If
                        Next
                    End If

                    CMain.InformUser(String.Format(CMain._T(TX.PT3D_EDITDOK), iT))
                    acTrans.Commit()
                    Exit Try
                Catch ex As System.Exception
                    acTrans.Abort()
                    CMain.DebugException(ex)
                End Try
            End Using

        Catch ex As System.Exception
            CMain.DebugException(ex)
        End Try
        GC.Collect()
        GC.WaitForPendingFinalizers()
    End Sub
    '// ===================================================================== '

#End Region


#Region "Public general purpose Functions"

    '// --------------------------------------------------------------------- '
    Public Shared Function GetSepStr(ByRef sIn As String) As String
        Dim IntV As Long
        IntV = AscW(sIn)
        If (IntV = AscW(" ")) Then
            Return ("<" & CMain._T(TX.SPACE) & ">")
        ElseIf (IntV = 9) Then
            Return ("<Tab>")
        ElseIf (IntV < 32) Then
            Return ("<" & CStr(IntV) & ">")
        Else
            Return sIn
        End If
    End Function
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    Public Shared Function GetSepFromStr(ByRef sIn As String) As String
        Dim sInside As String
        If (sIn.Length > 1) Then
            sInside = sIn.Trim
            If (sInside.StartsWith("<") AndAlso sInside.EndsWith(">")) Then
                sInside = sInside.Substring(1, sInside.Length - 2).ToUpper()
                If (IsNumeric(sInside)) Then
                    Dim lNr As Integer = CInt(sInside)
                    If (lNr >= 0 And lNr < 256) Then
                        Return Chr(lNr)
                    End If
                ElseIf (sInside = "TAB") Then
                    Return Chr(9)
                ElseIf (sInside = CMain._T(TX.SPACE).ToUpper()) Then
                    Return " "
                End If
            End If
        End If
        Return sIn
    End Function
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    Public Shared Function GetOrdFormStr(ByRef sIn As String) As PT3PART
        Select Case sIn
            Case CMain._T(TX.NAME)
                Return PT3PART.NAME
            Case CMain._T(TX.NORTH)
                Return PT3PART.NORTH
            Case CMain._T(TX.EAST)
                Return PT3PART.EAST
            Case CMain._T(TX.HEIGHT)
                Return PT3PART.HEIGHT
            Case CMain._T(TX.DESCR)
                Return PT3PART.DESCR
        End Select
        Return PT3PART.COUNT
    End Function
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    Public Shared Function GetStrFormOrd(ByVal iIn As PT3PART) As String
        Select Case iIn
            Case PT3PART.NAME
                Return CMain._T(TX.NAME)
            Case PT3PART.NORTH
                Return CMain._T(TX.NORTH)
            Case PT3PART.EAST
                Return CMain._T(TX.EAST)
            Case PT3PART.HEIGHT
                Return CMain._T(TX.HEIGHT)
            Case PT3PART.DESCR
                Return CMain._T(TX.DESCR)
        End Select
        Return Nothing
    End Function
    '// ===================================================================== '

#End Region


#Region "Private general purpose Functions"


    '// --------------------------------------------------------------------- '
    '// This function saves current settings
    Private Shared Sub SaveSett()
        Try
            CSett.SaveStg(sAPPNAME, "Stgs.DecSep", Stgs.DecSep)
            Dim i As Integer = 0
            For i = 0 To UBound(Stgs.FSep)
                CSett.SaveStg(sAPPNAME, "Stgs.FSep" & (i + 1).ToString, Stgs.FSep(i))
            Next i

            CSett.SaveStg(sAPPNAME, "Stgs.FSep" & (i + 1).ToString, "END")
            Dim tmps As String = ""
            Dim tmps2 As String = ""
            For i = 0 To PT3PART.COUNT - 1
                tmps2 = CStr(CInt(Stgs.FOrd(i)))
                If (tmps2.Length = 1) Then
                    tmps2 = "0" & tmps2
                End If
                tmps = tmps & tmps2
            Next
            CSett.SaveStg(sAPPNAME, "Stgs.FOrd", tmps)

            CSett.SaveStg(sAPPNAME, "Stgs.LastImpFile", Stgs.LastImpFile)
            CSett.SaveStg(sAPPNAME, "Stgs.LastExpFile", Stgs.LastExpFile)

            CSett.SaveStg(sAPPNAME, "Stgs.lyMark", Stgs.lyMark)
            CSett.SaveStg(sAPPNAME, "Stgs.lyNr", Stgs.lyNr)
            CSett.SaveStg(sAPPNAME, "Stgs.lyZ", Stgs.lyZ)
            CSett.SaveStg(sAPPNAME, "Stgs.lyCode", Stgs.lyCode)

            CSett.SaveStg(sAPPNAME, "Stgs.doBlock", Stgs.doBlock)
            CSett.SaveStg(sAPPNAME, "Stgs.sBlockName", Stgs.sBlockName)

            CSett.SaveStg(sAPPNAME, "Stgs.txH", Stgs.txH)
            CSett.SaveStg(sAPPNAME, "Stgs.sTxSty", Stgs.sTxSty)

            CSett.SaveStg(sAPPNAME, "Stgs.bIgnErr", Stgs.bIgnErr)

            CSett.SaveStg(sAPPNAME, "Stgs.iRstPos", Stgs.iRstPos)

            CSett.SaveStg(sAPPNAME, "Stgs.sNameSave", Stgs.sNameSave)
            CSett.SaveStg(sAPPNAME, "Stgs.dSaveZ", Stgs.dSaveZ)

            CSett.SaveStg(sAPPNAME, "Stgs.bHFromPoly", Stgs.bHFromPoly)
            CSett.SaveStg(sAPPNAME, "Stgs.bUsePtNr", Stgs.bUsePtNr)
            CSett.SaveStg(sAPPNAME, "Stgs.bAllowNonUniq", Stgs.bAllowNonUniq)

            CSett.SaveStg(sAPPNAME, "Stgs.sFormCoord", Stgs.sFormCoord)

        GC.Collect()
        GC.WaitForPendingFinalizers()
        Catch ex As System.Exception
            CMain.DebugException(ex)
        End Try
    End Sub
    '// ===================================================================== '


    '// --------------------------------------------------------------------- '
    '// This function loads current settings
    Private Shared Sub GetSett()
        Try
            Dim i As Integer, sRes As String
            For i = 0 To PT3PART.COUNT - 1
                Stgs.FOrd(i) = DirectCast(i, PT3PART)
            Next

            Stgs.DecSep = CSett.GetStrStg(sAPPNAME, "Stgs.DecSep", ".")
            ReDim Stgs.FSep(-1)
            For i = 0 To 100
                sRes = CSett.GetStrStg(sAPPNAME, "Stgs.FSep" & (i + 1).ToString, "END")
                If (sRes = "END") Then Exit For
                If (Stgs.FSep Is Nothing) Then GoTo NoArray_MF
                If (UBound(Stgs.FSep) = -1) Then
NoArray_MF:
                    ReDim Stgs.FSep(0 To 0)
                Else
                    ReDim Preserve Stgs.FSep(0 To UBound(Stgs.FSep) + 1)
                End If
                Stgs.FSep(UBound(Stgs.FSep)) = sRes
            Next
            If (i = 0) Then
                ReDim Stgs.FSep(0 To 2)
                Stgs.FSep(0) = vbTab
                Stgs.FSep(1) = " "
                Stgs.FSep(2) = ","
            End If

            sRes = CSett.GetStrStg(sAPPNAME, "Stgs.FOrd", "0001020304050607080910111213141516")
            Dim tmps2 As String
            For i = 0 To PT3PART.COUNT - 1
                If (sRes.Length < i * 2 + 2) Then Exit For
                tmps2 = sRes.Substring(i * 2, 2)
                If (IsNumeric(tmps2) = False) Then Exit For
                Stgs.FOrd(i) = DirectCast(CInt(tmps2), PT3PART)
            Next

            Stgs.LastImpFile = CSett.GetStrStg(sAPPNAME, "Stgs.LastImpFile", "")
            Stgs.LastExpFile = CSett.GetStrStg(sAPPNAME, "Stgs.LastExpFile", "")


            Stgs.lyMark = CSett.GetStrStg(sAPPNAME, "Stgs.lyMark", "0")
            Stgs.lyNr = CSett.GetStrStg(sAPPNAME, "Stgs.lyNr", "0")
            Stgs.lyZ = CSett.GetStrStg(sAPPNAME, "Stgs.lyZ", "0")
            Stgs.lyCode = CSett.GetStrStg(sAPPNAME, "Stgs.lyCode", "0")

            Stgs.doBlock = CSett.GetBolStg(sAPPNAME, "Stgs.doBlock", True)
            Stgs.sBlockName = CSett.GetStrStg(sAPPNAME, "Stgs.sBlockName", "PCT3D")

            Stgs.txH = CSett.GetDblStg(sAPPNAME, "Stgs.txH", 0.2)
            Stgs.sTxSty = CSett.GetStrStg(sAPPNAME, "Stgs.sTxSty", "Standard")

            Stgs.bIgnErr = CSett.GetBolStg(sAPPNAME, "Stgs.bIgnErr", True)

            Stgs.iRstPos = CSett.GetIntStg(sAPPNAME, "Stgs.iRstPos", 3)

            If (Stgs.lyMark = "") Then
                Stgs.lyMark = "0"
            End If
            If (Stgs.lyNr = "") Then
                Stgs.lyNr = "0"
            End If
            If (Stgs.lyZ = "") Then
                Stgs.lyZ = "0"
            End If
            If (Stgs.lyCode = "") Then
                Stgs.lyCode = "0"
            End If
            If (Stgs.sBlockName = "") Then
                Stgs.sBlockName = "PCT3D"
            End If

            Stgs.sNameSave = CSett.GetStrStg(sAPPNAME, "Stgs.sNameSave", "100")
            Stgs.dSaveZ = CSett.GetDblStg(sAPPNAME, "Stgs.dSaveZ", 0)

            Stgs.bHFromPoly = CSett.GetBolStg(sAPPNAME, "Stgs.bHFromPoly", True)
            Stgs.bUsePtNr = CSett.GetBolStg(sAPPNAME, "Stgs.bUsePtNr", True)
            Stgs.bAllowNonUniq = CSett.GetBolStg(sAPPNAME, "Stgs.bAllowNonUniq", False)

            Stgs.sFormCoord = CSett.GetStrStg(sAPPNAME, "Stgs.sFormCoord", "0.000")

        Catch ex As System.Exception
            CMain.DebugException(ex)
        End Try
    End Sub
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    '// This function shows current settings
    Private Shared Function PrintStg(ByRef lcStg As PT3DSTG) As String
        Dim sRet As String
        Dim sSep As String
        Dim i As Integer

        sRet = _
   vbCrLf & CMain._T(TX.CSTG) & sAPPNAME & ": " & vbCrLf & _
    CMain._T(TX.DECSEP) & " = " & lcStg.DecSep & vbCrLf & _
          CMain._T(TX.FLDSEP) & " = "
        If (UBound(lcStg.FSep) > 0) Then
            sRet = sRet & GetSepStr(lcStg.FSep(0))
            For i = 1 To UBound(lcStg.FSep)
                sSep = lcStg.FSep(i)
                sRet = sRet & " " & _
             GetSepStr(lcStg.FSep(i))
            Next
        End If
        sRet = sRet & _
    CMain._T(TX.PT3D_LASTI) & " = " & lcStg.LastImpFile & vbCrLf & _
    CMain._T(TX.PT3D_LASTE) & " = " & lcStg.LastExpFile & vbCrLf & _
 _
    CMain._T(TX.LAYFOR) & ":" & vbCrLf & _
    vbTab & CMain._T(TX.MARKER) & " = " & lcStg.lyMark & vbCrLf & _
    vbTab & CMain._T(TX.NAME) & " = " & lcStg.lyNr & vbCrLf & _
    vbTab & CMain._T(TX.HEIGHT) & " = " & lcStg.lyZ & vbCrLf & _
    vbTab & CMain._T(TX.DESCR) & " = " & lcStg.lyCode & vbCrLf & _
 _
    CMain._T(TX.CREATEBLK) & " = " & CStr(lcStg.doBlock) & vbCrLf & _
    CMain._T(TX.BLKNAME) & " = " & lcStg.sBlockName & vbCrLf & _
 _
    CMain._T(TX.HTEXT) & " = " & _
      lcStg.txH.ToString("0.000") & vbCrLf & _
    CMain._T(TX.STYLE) & " = " & lcStg.sTxSty & vbCrLf & _
    CMain._T(TX.PTNR) & " = " & lcStg.sNameSave & vbCrLf & _
    CMain._T(TX.HEIGHT) & " = " & lcStg.dSaveZ.ToString() & vbCrLf & _
 _
    CMain._T(TX.IGNERR) & " = " & CStr(lcStg.bIgnErr) & vbCrLf & _
    CMain._T(TX.COORDFORM) & " = " & lcStg.sFormCoord & vbCrLf


        '// 0 - no reset
        '// 1 - reset
        '// 2 - only moved
        '// 3 - smart
        Select Case lcStg.iRstPos
            Case 0
                sRet = sRet & _
                    CMain._T(TX.PTS_NORST) & vbCrLf
            Case 1
                sRet = sRet & _
                    CMain._T(TX.PTS_RSTPOS) & vbCrLf
            Case 2
                sRet = sRet & _
                    CMain._T(TX.PTS_RSTUNM) & vbCrLf
            Case 3
                sRet = sRet & _
                    CMain._T(TX.PTS_RSTSMART) & vbCrLf
        End Select

        Return sRet
    End Function
    '// ===================================================================== '

#End Region


#Region "Common interface" ' -----------------------

    '// --------------------------------------------------------------------- '
    '// a new instance is created
    Public Sub New()
        Try
            sAPPTIP = CMain._T(TX.PT3D_INFO)
            Return
        Catch ex As System.Exception
            CMain.DebugException(ex)
            Return
        End Try
    End Sub
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    '// the module is asked to terminate
    Public Overrides Function Terminate() As Boolean
        Try
            SaveSett()
            Return True
        Catch ex As System.Exception
            CMain.DebugException(ex)
            Return False
        End Try
    End Function
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    '// the module is asked to tell it's name
    Public Shared Function GetName() As String
        Return sAPPNAME
    End Function
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    '// the module is asked to tell about itself
    Public Shared Sub GetInfos(ByRef sName As String, _
                               ByRef sVer As String, _
                               ByRef sTip As String)
        sName = sAPPNAME
        sVer = sAPPVER
        sTip = CMain._T(TX.PT3D_INFO)
    End Sub
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    '// the module is asked to tell about itself
    Public Shared Function GetDescription() As String
        Dim sOut As String = sAPPNAME
        Try
            Dim cIni As New IniWork(CApp.sAppPath & CMain.APPSTG)
            If cIni.HasErrors = True Then Exit Try
            sOut = cIni.Read(sAPPNAME, CMain.DESCRKEY & _
                             CMain.eAppLang.ToString,sAPPNAME)
        Catch ex As System.Exception
            CMain.DebugException(ex)
        End Try
        Return sOut
    End Function
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    '// the module is informed about application start-up
    Public Shared Sub DoPrereq()
        Try
            ' this function is called at application start-up in order to 
            ' allow applications to do any prerequisites
            ' there is no instance of this class at this time
            ReDim Stgs.FOrd(PT3PART.COUNT - 1)
            GetSett()
        Catch ex As System.Exception
            CMain.DebugException(ex)
        End Try
        Return
    End Sub
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    '// create the user interface for this module
    Public Shared Sub DoCUI( _
     ByRef pcs As CustomizationSection, _
     ByRef mg As MacroGroup)
        ' this function is called when a CUI is builded in order to
        ' allow any application specifics
        Try
#If HARDCORE_CUI Then
            If CApp.cuiCl Is Nothing Then Exit Try
            CApp.cuiCl.AddMacro(sCMD_IMPORT,   "PT_Import")
            CApp.cuiCl.AddMacro(sCMD_EXPORT,   "PT_Export")
            CApp.cuiCl.AddMacro(sCMD_EXPLODE,  "PT_Explode")
            CApp.cuiCl.AddMacro(sCMD_EDIT,     "PT_Edit")
            CApp.cuiCl.AddMacro(sCMD_SETTINGS, "PT_Settings")
            CApp.cuiCl.AddMacro(sCMD_POLYPT,   "PT_Poly")
            CApp.cuiCl.AddMacro(sCMD_DIST,     "PT_Dist")
            CApp.cuiCl.AddMacro(sCMD_INTERM,   "PT_Span")


            CApp.cuiCl.AddToolbar( _
                sAPPNAME, _
                Application.MainWindow.Location.X, _
                100 + MIDS.FSK_PT3D * 30)
            CApp.cuiCl.AddToolbarBtn(CMain._T(TX.IMPORT), sCMD_IMPORT)
            CApp.cuiCl.AddToolbarBtn(CMain._T(TX.EXPORT), sCMD_EXPORT)
            CApp.cuiCl.AddToolbarBtn(CMain._T(TX.EXPLODE), sCMD_EXPLODE)
            CApp.cuiCl.AddToolbarBtn(CMain._T(TX.EDIT), sCMD_EDIT)
            CApp.cuiCl.AddToolbarSep()
            CApp.cuiCl.AddToolbarBtn(CMain._T(TX.POLYPTS), sCMD_POLYPT)
            CApp.cuiCl.AddToolbarSep()
            CApp.cuiCl.AddToolbarBtn(CMain._T(TX.SETTINGS), sCMD_SETTINGS)

            CApp.cuiCl.AddToolbar( _
                sAPPNAME & "_Ext", _
                Application.MainWindow.Location.X, _
                500 + MIDS.FSK_PT3D * 30)
            CApp.cuiCl.AddToolbarBtn(CMain._T(TX.DIST), sCMD_DIST)
            CApp.cuiCl.AddToolbarBtn(CMain._T(TX.ONINTERV), sCMD_INTERM)

#Else

			Dim mm1 As MenuMacro = Nothing
			mm1 = New MenuMacro(mg, sCMD_IMPORT, "^C^C" & sCMD_IMPORT, "ID_" & sCMD_IMPORT)
			mm1 = New MenuMacro(mg, sCMD_EXPORT, "^C^C" & sCMD_EXPORT, "ID_" & sCMD_EXPORT)
			mm1 = New MenuMacro(mg, sCMD_EXPLODE, "^C^C" & sCMD_EXPLODE, "ID_" & sCMD_EXPLODE)
			mm1 = New MenuMacro(mg, sCMD_EDIT, "^C^C" & sCMD_EDIT, "ID_" & sCMD_EDIT)
			mm1 = New MenuMacro(mg, sCMD_POLYPT, "^C^C" & sCMD_POLYPT, "ID_" & sCMD_POLYPT)
			mm1 = New MenuMacro(mg, sCMD_SETTINGS, "^C^C" & sCMD_SETTINGS, "ID_" & sCMD_SETTINGS)

			mm1 = New MenuMacro(mg, sCMD_DIST, "^C^C" & sCMD_DIST, "ID_" & sCMD_DIST)
			mm1 = New MenuMacro(mg, sCMD_INTERM, "^C^C" & sCMD_INTERM, "ID_" & sCMD_INTERM)

			Dim tbBtn As ToolbarButton = Nothing
			Dim newTb As Toolbar = New Toolbar(sAPPNAME, pcs.MenuGroup)
			newTb.ElementID = "EID_TNIK_3DPT"
			newTb.ToolbarOrient = ToolbarOrient.floating
			newTb.ToolbarVisible = ToolbarVisible.show
            newTb.XCoordinate = Application.MainWindow.Location.X
            newTb.YCoordinate = 100 + MIDS.FSK_PT3D * 30

			tbBtn = New ToolbarButton(newTb, -1)
			tbBtn.Name = CMain._T(tx.IMPORT)
			tbBtn.MacroID = "ID_" & sCMD_IMPORT
			tbBtn = New ToolbarButton(newTb, -1)
			tbBtn.Name = CMain._T(tx.EXPORT)
			tbBtn.MacroID = "ID_" & sCMD_EXPORT
			tbBtn = New ToolbarButton(newTb, -1)
			tbBtn.Name = CMain._T(tx.EXPLODE)
			tbBtn.MacroID = "ID_" & sCMD_EXPLODE
			tbBtn = New ToolbarButton(newTb, -1)
			tbBtn.Name = CMain._T(tx.EDIT)
			tbBtn.MacroID = "ID_" & sCMD_EDIT
			tbBtn = New ToolbarButton(newTb, -1)
			tbBtn = New ToolbarButton(newTb, -1)
			tbBtn.Name = CMain._T(tx.POLYPTS)
			tbBtn.MacroID = "ID_" & sCMD_POLYPT
			tbBtn = New ToolbarButton(newTb, -1)
			tbBtn = New ToolbarButton(newTb, -1)
			tbBtn.Name = CMain._T(tx.SETTINGS)
			tbBtn.MacroID = "ID_" & sCMD_SETTINGS


			Dim tbBtn As ToolbarButton = Nothing
			Dim newTb As Toolbar = New Toolbar(sAPPNAME, pcs.MenuGroup)
			newTb.ElementID = "EID_TNIK_3DPT_Ext"
			newTb.ToolbarOrient = ToolbarOrient.floating
			newTb.ToolbarVisible = ToolbarVisible.show
            newTb.XCoordinate = Application.MainWindow.Location.X
            newTb.YCoordinate = 500 + MIDS.FSK_PT3D * 30

			tbBtn = New ToolbarButton(newTb, -1)
			tbBtn.Name = CMain._T(tx.DIST)
			tbBtn.MacroID = "ID_" & sCMD_DIST
			tbBtn = New ToolbarButton(newTb, -1)
			tbBtn.Name = CMain._T(tx.ONINTERV)
			tbBtn.MacroID = "ID_" & sCMD_INTERM

#End If

        Catch ex As System.Exception
            CMain.DebugException(ex)
        End Try
    End Sub
    '// ===================================================================== '


#End Region


#Region "Internal base work"

    ' -----------------------------------------------------------------------------------
    Private Shared Function Edit_Entity( _
            ByRef acDoc As Document, _
            ByRef acTrans As Transaction, _
            ByRef acBlkModel As BlockTableRecord, _
            ByRef oidTxSty As ObjectId, _
            ByRef oIdReference As ObjectId, _
            ByRef idBlkd As ObjectId, _
            ByRef lStgs As PT3DSTG) _
        As Boolean

        ' get the entity that this ID represents
        Dim Ent As DBObject
        Dim bres As Boolean = False
        Dim ptOut As FSK_PT3D
        Dim WShouldBe_N As Double
        Dim WShouldBe_E As Double
        Dim PrvTxH As Double

        Try
            Ent = acTrans.GetObject(idBlkd, OpenMode.ForRead)
            If Not TypeOf Ent Is BlockReference Then Exit Try
            ' "cast" the entity into a block reference
            Dim blkRef As BlockReference = DirectCast(Ent, BlockReference)
            ' see if this is our kind of block
            If blkRef.BlockTableRecord <> oIdReference Then Return False
            If blkRef.AttributeCollection.Count = 0 Then Exit Try

            Dim dXAl As Double = blkRef.Position.X + lStgs.txH * (5 / 8)
            '// Suplemental space between attributes
            Dim dSupl As Double = lStgs.txH / 6

            ' loop in dynamic properties
            ptOut.Name = ""
            ptOut.Descr = ""
            For Each acAtId As ObjectId In blkRef.AttributeCollection
                Dim acAtrRef As AttributeReference = DirectCast( _
                 acTrans.GetObject(acAtId, OpenMode.ForWrite),  _
                AttributeReference)
                acAtrRef.TextStyle = oidTxSty
                PrvTxH = acAtrRef.Height
                acAtrRef.Height = lStgs.txH
                '// 0 - no reset
                '// 1 - reset
                '// 2 - only moved
                '// 3 - smart
                WShouldBe_E = blkRef.Position.X + PrvTxH * (5 / 8)
                Select Case acAtrRef.Tag.ToUpper
                    Case sPTOA_NAME
                        acAtrRef.Layer = lStgs.lyNr

                        WShouldBe_N = blkRef.Position.Y + _
                                PrvTxH / 2 + _
                                PrvTxH / 6
                        Select Case lStgs.iRstPos
                            Case 0
                                '// no reset
                            Case 1
                                '// reset
                                Reset_Name:
                                acAtrRef.Position = New Point3d( _
                                    dXAl, _
                                    blkRef.Position.Y + _
                                        lStgs.txH / 2 + _
                                        dSupl, _
                                    0)
                            Case 2
                                '// only moved
                                If Math.Abs( _
                                    acAtrRef.Position.X - _
                                    WShouldBe_E) < CMain.MARGIN Then
                                If Math.Abs( _
                                    acAtrRef.Position.Y - _
                                    WShouldBe_N) < CMain.MARGIN Then
                                    '// in standard position
                                        GoTo Reset_Name
                                End If
                                End If
                                '// not in standard position
                                '// so do nothing
                            Case 3
                                '// smart
                                If Math.Abs( _
                                    acAtrRef.Position.X - _
                                    WShouldBe_E) < CMain.MARGIN Then
                                If Math.Abs( _
                                    acAtrRef.Position.Y - _
                                    WShouldBe_N) < CMain.MARGIN Then
                                    '// in standard position
                                        GoTo Reset_Z
                                End If
                                End If
                                '// not in standard position
                                '// get smarter
                                
                        End Select
                    Case sPTOA_Z
                        acAtrRef.Layer = lStgs.lyZ

                        WShouldBe_N = blkRef.Position.Y - _
                                PrvTxH / 2
                        Select Case lStgs.iRstPos
                            Case 0
                                '// no reset
                            Case 1
                                '// reset
                                Reset_Z:
                                acAtrRef.Position = New Point3d(dXAl, _
                                        blkRef.Position.Y - _
                                        lStgs.txH / 2, _
                                        0)
                            Case 2
                                '// only moved
                                If Math.Abs( _
                                    acAtrRef.Position.X - _
                                    WShouldBe_E) < CMain.MARGIN Then
                                If Math.Abs( _
                                    acAtrRef.Position.Y - _
                                    WShouldBe_N) < CMain.MARGIN Then
                                    '// in standard position
                                        GoTo Reset_Z
                                End If
                                End If
                                '// not in standard position
                                '// so do nothing
                            Case 3
                                '// smart
                                If Math.Abs( _
                                    acAtrRef.Position.X - _
                                    WShouldBe_E) < CMain.MARGIN Then
                                If Math.Abs( _
                                    acAtrRef.Position.Y - _
                                    WShouldBe_N) < CMain.MARGIN Then
                                    '// in standard position
                                        GoTo Reset_Z
                                End If
                                End If
                                '// not in standard position
                                '// get smarter
                                
                        End Select
                    Case sPTOA_CODE
                        acAtrRef.Layer = lStgs.lyCode
                        WShouldBe_N = blkRef.Position.Y - _
                                ( 3 * PrvTxH / 2 + PrvTxH / 6)
                        Select Case lStgs.iRstPos
                            Case 0
                                '// no reset
                            Case 1
                                '// reset
                                Reset_Code:
                                acAtrRef.Position = New Point3d( _
                                    dXAl, _
                                    blkRef.Position.Y - _
                                    (3 * lStgs.txH / 2 + dSupl), _
                                    0)
                            Case 2
                                '// only moved
                                If Math.Abs( _
                                    acAtrRef.Position.X - _
                                    WShouldBe_E) < CMain.MARGIN Then
                                If Math.Abs( _
                                    acAtrRef.Position.Y - _
                                    WShouldBe_N) < CMain.MARGIN Then
                                    '// in standard position
                                        GoTo Reset_Code
                                End If
                                End If
                                '// not in standard position
                                '// so do nothing
                            Case 3
                                '// smart
                                If Math.Abs( _
                                    acAtrRef.Position.X - _
                                    WShouldBe_E) < CMain.MARGIN Then
                                If Math.Abs( _
                                    acAtrRef.Position.Y - _
                                    WShouldBe_N) < CMain.MARGIN Then
                                    '// in standard position
                                        GoTo Reset_Code
                                End If
                                End If
                                '// not in standard position
                                '// get smarter
                                
                        End Select
                End Select
            Next
            bres = True
        Catch
        End Try
        GC.Collect()
        GC.WaitForPendingFinalizers()
        Return bres
    End Function
    ' ===================================================================================

    ' -----------------------------------------------------------------------------------
    Private Function Explode_Entity( _
            ByRef acDoc As Document, _
            ByRef acTrans As Transaction, _
            ByRef acBlkModel As BlockTableRecord, _
            ByRef oIdReference As ObjectId, _
            ByRef idBlkd As ObjectId) _
        As Boolean

        ' get the entity that this ID represents
        Dim Ent As DBObject
        Dim bres As Boolean = False
        Dim Pct As Point3d

        Try
            '// get a reference to table of blocks
            Dim acBlkTbl As BlockTable = DirectCast( _
                    acTrans.GetObject(acDoc.Database.BlockTableId, _
                                      OpenMode.ForRead),  _
                BlockTable)

            Ent = acTrans.GetObject(idBlkd, OpenMode.ForRead)
            If Not TypeOf Ent Is BlockReference Then Exit Try
            ' "cast" the entity into a block reference
            Dim blkRef As BlockReference = DirectCast(Ent, BlockReference)
            ' see if this is our kind of block
            If blkRef.BlockTableRecord <> oIdReference Then Return False
            If blkRef.AttributeCollection.Count = 0 Then Exit Try

            ' loop in dynamic properties
            Dim acAtrRef_Name As AttributeReference = Nothing
            Dim acAtrRef_Z As AttributeReference = Nothing
            Dim acAtrRef_Code As AttributeReference = Nothing
            For Each acAtId As ObjectId In blkRef.AttributeCollection
                Dim acAtrRef As AttributeReference = DirectCast( _
                 acTrans.GetObject(acAtId, OpenMode.ForRead),  _
                AttributeReference)
                Select Case acAtrRef.Tag.ToUpper
                    Case sPTOA_NAME
                        acAtrRef_Name = acAtrRef
                    Case sPTOA_Z
                        acAtrRef_Z = acAtrRef
                    Case sPTOA_CODE
                        acAtrRef_Code = acAtrRef
                End Select
            Next
            Pct = New Point3d( _
                    blkRef.Position.X, _
                    blkRef.Position.Y, _
                    blkRef.Position.Z)


            ' Step 1: Create a circle entity - the marker
            Dim acCirc As Circle = New Circle
            acCirc.SetDatabaseDefaults()
            acCirc.Center = Pct
            acCirc.Layer = blkRef.Layer
            acCirc.Radius = (Stgs.txH / 3) * blkRef.ScaleFactors.X
            acBlkModel.AppendEntity(acCirc)
            acTrans.AddNewlyCreatedDBObject(acCirc, True)

            ' Step 2: Create a point entity - the marker
            Dim acPt As DBPoint = New DBPoint
            acPt.SetDatabaseDefaults()
            acPt.Position = Pct
            acPt.Layer = blkRef.Layer
            acBlkModel.AppendEntity(acPt)
            acTrans.AddNewlyCreatedDBObject(acPt, True)

            ' Step 3: Create attributes
            Dim acText As DBText
        
            '   3.1 Name
            If acAtrRef_Name <> Nothing Then
                acText = New DBText()
                acText.SetDatabaseDefaults()
                With acAtrRef_Name
                    acText.TextString = .TextString
                    acText.Position = .Position
                    acText.Layer = .Layer
                    acText.TextStyle = .TextStyle
                    acText.Height = .Height
                    acText.HorizontalMode = .HorizontalMode
                    acText.VerticalMode = .VerticalMode
                End With
                acBlkModel.AppendEntity(acText)
                acTrans.AddNewlyCreatedDBObject(acText, True)
            End If

            '   3.2 Z - Height
            If acAtrRef_Z <> Nothing Then
                acText = New DBText()
                acText.SetDatabaseDefaults()
                With acAtrRef_Z
                    acText.TextString = .TextString
                    acText.Position = .Position
                    acText.Layer = .Layer
                    acText.TextStyle = .TextStyle
                    acText.Height = .Height
                    acText.HorizontalMode = .HorizontalMode
                    acText.VerticalMode = .VerticalMode
                End With
                acBlkModel.AppendEntity(acText)
                acTrans.AddNewlyCreatedDBObject(acText, True)
            End If

            '   3.3 Code - Description
            If acAtrRef_Code <> Nothing Then
                acText = New DBText()
                acText.SetDatabaseDefaults()
                With acAtrRef_Code
                    acText.TextString = .TextString
                    acText.Position = .Position
                    acText.Layer = .Layer
                    acText.TextStyle = .TextStyle
                    acText.Height = .Height
                    acText.HorizontalMode = .HorizontalMode
                    acText.VerticalMode = .VerticalMode
                End With
                acBlkModel.AppendEntity(acText)
                acTrans.AddNewlyCreatedDBObject(acText, True)
            End If


            blkRef.UpgradeOpen()
            blkRef.Erase(True)
            bres = True

        Catch ex As System.Exception
            CMain.DebugException(ex)
        End Try
        GC.Collect()
        GC.WaitForPendingFinalizers()
        Return bres
    End Function
    ' ===================================================================================

    ' -----------------------------------------------------------------------------------
    Private Shared Function Export_txt_Unit( _
     ByRef acTrans As Transaction, _
     ByRef objWRi As System.IO.StreamWriter, _
     ByRef sSep As String, _
     ByRef oIdTarg As ObjectId, _
     ByRef idBlkd As ObjectId, _
     ByRef lcStgs as PT3DSTG _
      ) As Boolean

        ' get the entity that this ID represents
        Dim Ent As DBObject
        Dim sForm As String
        If (String.IsNullOrEmpty(lcStgs.sFormCoord)) Then
            sForm = "0.000"
        Else
            sForm = lcStgs.sFormCoord
        End If

        Try
            Ent = acTrans.GetObject(idBlkd, OpenMode.ForRead)
        Catch
            Return False
        End Try
        If TypeOf Ent Is BlockReference Then
            ' "cast" the entity into a block reference
            Dim blkRef As BlockReference = DirectCast(Ent, BlockReference)
            '' see if this is our kind of block
            If blkRef.BlockTableRecord <> oIdTarg Then Return False
            If blkRef.AttributeCollection.Count = 0 Then Return False

            ' prepare the properties  list
            Dim sName As String
            Dim sCode As String
            ' loop in dynamic properties
            sName = ""
            sCode = ""
            For Each acAtId As ObjectId In blkRef.AttributeCollection
                Dim acAtrRef As AttributeReference = _
                 DirectCast(acTrans.GetObject(acAtId, OpenMode.ForRead),  _
                 AttributeReference)
                Select Case acAtrRef.Tag.ToUpper
                    Case sPTOA_NAME
                        sName = acAtrRef.TextString
                        'Case sPTOA_Z
                    Case sPTOA_CODE
                        sCode = acAtrRef.TextString
                End Select
            Next



            objWRi.WriteLine( _
             sName & sSep & _
             blkRef.Position.Y.ToString(sForm) & sSep & _
             blkRef.Position.X.ToString(sForm) & sSep & _
             blkRef.Position.Z.ToString(sForm) & sSep & _
             sCode)

        End If
        GC.Collect()
        GC.WaitForPendingFinalizers()
        Return True
    End Function
    ' ===================================================================================

    ' -----------------------------------------------------------------------------------
    Private Shared Function Export_EX_Unit( _
     ByVal acTrans As Transaction, _
     ByVal ExcelSheet As XLS, _
     ByRef i As Integer, _
     ByRef oIdTarg As ObjectId, _
     ByVal idBlkd As ObjectId _
      ) As Boolean
        ' get the entity that this ID represents
        Dim Ent As DBObject
        Try
            Ent = acTrans.GetObject(idBlkd, OpenMode.ForRead)
        Catch
            Return False
        End Try
        If TypeOf Ent Is BlockReference Then
            ' "cast" the entity into a block reference
            Dim blkRef As BlockReference = DirectCast(Ent, BlockReference)
            '' see if this is our kind of block
            If blkRef.BlockTableRecord <> oIdTarg Then Return False
            If blkRef.AttributeCollection.Count = 0 Then Return False
            ' prepare the properties  list
            Dim sName As String
            Dim sCode As String
            ' loop in dynamic properties
            sName = ""
            sCode = ""
            For Each acAtId As ObjectId In blkRef.AttributeCollection
                Dim acAtrRef As AttributeReference = _
                 DirectCast(acTrans.GetObject(acAtId, OpenMode.ForRead),  _
                 AttributeReference)
                Select Case acAtrRef.Tag.ToUpper
                    Case sPTOA_NAME
                        sName = acAtrRef.TextString
                        'Case sPTOA_Z
                    Case sPTOA_CODE
                        sCode = acAtrRef.TextString
                End Select
            Next
            With ExcelSheet
                .SetCV(i, 1, sName)
                .SetCV(i, 2, blkRef.Position.Y)
                .SetCV(i, 3, blkRef.Position.X)
                .SetCV(i, 4, blkRef.Position.Z)
                .SetCV(i, 5, sCode)

                i = i + 1
            End With
        End If
        GC.Collect()
        GC.WaitForPendingFinalizers()
        Return True
    End Function
    ' ===================================================================================

    ' -----------------------------------------------------------------------------------
    Private Shared Function Export_Clp_Unit( _
     ByVal acTrans As Transaction, _
     ByRef sOut As String, _
     ByRef sSep As String, _
     ByRef oIdTarg As ObjectId, _
     ByVal idBlkd As ObjectId, _
     ByRef lcStgs as PT3DSTG _
      ) As Boolean

        ' get the entity that this ID represents
        Dim Ent As DBObject
        Try
            Ent = acTrans.GetObject(idBlkd, OpenMode.ForRead)
        Catch
            Return False
        End Try
        Dim sForm As String
        If (String.IsNullOrEmpty(lcStgs.sFormCoord)) Then
            sForm = "0.000"
        Else
            sForm = lcStgs.sFormCoord
        End If

        If TypeOf Ent Is BlockReference Then
            ' "cast" the entity into a block reference
            Dim blkRef As BlockReference = DirectCast(Ent, BlockReference)
            '' see if this is our kind of block
            If blkRef.BlockTableRecord <> oIdTarg Then Return False
            If blkRef.AttributeCollection.Count = 0 Then Return False
            ' prepare the properties  list
            Dim sName As String
            Dim sCode As String
            ' loop in dynamic properties
            sName = ""
            sCode = ""
            For Each acAtId As ObjectId In blkRef.AttributeCollection
                Dim acAtrRef As AttributeReference = _
                 DirectCast(acTrans.GetObject(acAtId, OpenMode.ForRead),  _
                 AttributeReference)
                Select Case acAtrRef.Tag.ToUpper
                    Case sPTOA_NAME
                        sName = acAtrRef.TextString
                        'Case sPTOA_Z
                    Case sPTOA_CODE
                        sCode = acAtrRef.TextString
                End Select
            Next
            sOut = sOut & _
    sName & sSep & _
    blkRef.Position.Y.ToString("0.000") & sSep & _
    blkRef.Position.X.ToString("0.000") & sSep & _
    blkRef.Position.Z.ToString("0.000") & sSep & _
    sCode & vbNewLine
        End If
        GC.Collect()
        GC.WaitForPendingFinalizers()
        Return True
    End Function
    ' ===================================================================================

    '// --------------------------------------------------------------------- '
    '// Given a string, a code and a point structure, it interprets
    Private Shared Function GetRealNr( _
        ByRef sIni As String, _
        ByVal sSep As String, _
        ByRef dOut As Double) _
        As Boolean

        Dim sTmp As String = sIni.Trim()
        Try
            Dim iOcr As Integer = sTmp.IndexOf(sSep)
            If iOcr = -1 Then
                dOut = CDbl(sTmp)
                Return True
            Else
                Dim p1 As Long = CLng(sTmp.Substring(0, iOcr))
                Dim sTst As String = sTmp.Substring(iOcr + 1)
                Dim p2 As Long = CLng(sTst)
                If (p2 < 0) Then Return False
                iOcr = sTst.Length
                If (iOcr = 0) Then
                    dOut = CDbl(p1)
                Else
                    dOut = CDbl(p1) + CDbl(p2) / (10 ^ iOcr)
                End If
#If DEBUG Then
                Dim form As String = ""
                Dim i As Integer
                For i = 1 To iOcr
                    form = form & "0"
                Next i
                form = "0" & sSep & form
                If (dOut.ToString(form) <> sTmp) Then
                    i = 0
                    form = (iOcr / i).ToString()
                End If
#End If
                Return True
            End If
        Catch ex As System.Exception
            CMain.DebugException(ex)
        End Try
        GC.Collect()
        GC.WaitForPendingFinalizers()
        Return False
    End Function
    '// ===================================================================== '


    '// --------------------------------------------------------------------- '
    '// Given a string, a code and a point structure, it interprets
    Private Shared Function TokString( _
        ByRef sIn As String, _
        ByVal eTy As PT3PART, _
        ByVal sDecS As String, _
        ByRef ptOut As FSK_PT3D) As Boolean

        Select Case eTy
            Case PT3PART.NAME
                ptOut.Name = sIn
            Case PT3PART.DESCR
                ptOut.Descr = sIn
            Case PT3PART.NORTH
                Return GetRealNr(sIn, sDecS, ptOut.North)
            Case PT3PART.EAST
                Return GetRealNr(sIn, sDecS, ptOut.East)
            Case PT3PART.HEIGHT
                Return GetRealNr(sIn, sDecS, ptOut.Height)
        End Select
        Return True
    End Function
    '// ===================================================================== '




    'using System;

    '    Class Test
    '{
    '    static void Main()
    '    {

    '      MyClass mc = new MyClass();
    '      aFuncDelegate afd = new aFuncDelegate(aFunc);
    '      mc.myFunc(afd, "Hello from aFunc");     
    '      Console.ReadLine();
    '    }

    '    static void aFunc(string a)
    '    {
    '      Console.WriteLine(a);
    '    } 
    '}

    'delegate void aFuncDelegate(string a);

    'class MyClass
    '{
    '   public void myFunc(aFuncDelegate afd, string someString)
    '   {
    '      afd(someString);
    '   }   
    '}






    '// --------------------------------------------------------------------- '
    '// The function that actually imports a file
    Public Shared Function ImportFile(ByRef sFile As String, _
                                    ByRef lStgs As PT3DSTG, _
                                    Optional ByVal kb As Del_ImpPt = Nothing) _
                                    As Boolean
        Dim bRet As Boolean = False
        Dim ExpTy As Integer
        Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
        Dim srFileReader As System.IO.StreamReader = Nothing
        Dim sInputLine As String
        Dim Parts() As String = Nothing
        Dim PartCnt As Integer
        Dim ptOut As FSK_PT3D
        Dim bNorth As Boolean
        Dim bEast As Boolean
        Dim PtCnt As Long = 0
        Dim PtErrCnt As Long = 0
        Dim j As Integer
        Dim sClipboard As String = ""
        Dim iClIdx As Integer
        Dim ExcelSheet As XLS = Nothing
        Dim ExcelWorkbook As XLW = Nothing
        Dim oObj As Object

        If (acDoc Is Nothing) Then
            Return False
        End If
        Using acLock As DocumentLock = acDoc.LockDocument
            ExpTy = EXP_TXT
            If (sFile.Length > 4) Then
                If ((sFile.Substring(sFile.Length - 4)).ToUpper() = ".XLS") Then
                    ExpTy = EXP_XL
                ElseIf sFile = sCLIPB Then
                    ExpTy = EXP_CLPB
                End If
            End If


            If (CreatePtBlock(lStgs, acDoc) = False) Then
                Return False
            End If

            Try
                If (lStgs.DecSep.Length = 0) Then
                    If ExpTy <> EXP_XL Then
                        CMain.AlertUser(TX.PT3D_EDEC)
                        Return False
                    End If
                End If
                If lStgs.FSep Is Nothing Then
                    If ExpTy <> EXP_XL Then
                        CMain.AlertUser(TX.PT3D_EFLD)
                        Return False
                    End If
                End If
                If (ExpTy <> EXP_CLPB) AndAlso (System.IO.File.Exists(sFile) = False) Then
                    Debug.Print("(ImportFile) File does not exists")
                    Return False
                End If


                If (ExpTy = EXP_TXT) Then
                    srFileReader = System.IO.File.OpenText(sFile)
                    sInputLine = srFileReader.ReadLine()
                ElseIf (ExpTy = EXP_CLPB) Then
                    sClipboard = Windows.Forms.Clipboard.GetText
                    sInputLine = CMain.NextLine(sClipboard, iClIdx)
                Else '//ExpTy = EXP_XL
                    ExcelWorkbook = New XLW(sFile)
                    If (ExcelWorkbook.ErrSts <> XLW.ERR.OK) Then
                        ExcelWorkbook.Close()
                        ExcelWorkbook = Nothing
                        Exit Try
                    End If
                    ExcelSheet = ExcelWorkbook.GetActiveSheet()
                    If (ExcelSheet Is Nothing) Then
                        ExcelSheet = Nothing
                        ExcelWorkbook.Close()
                        ExcelWorkbook = Nothing
                        Exit Try
                    End If

                    Dim i As Integer
                    Dim k As Integer
                    '// Loop-search first cell in first 100x100 cells
                    k = 1 : i = 1
                    oObj = ExcelSheet.GetCV(1, 1)
                    If Not (oObj Is Nothing) Then
                        If oObj.ToString <> "" Then
                            GoTo FoundCell
                        End If
                    End If

                    For i = 2 To 100
                        For k = 1 To i
                            oObj = ExcelSheet.GetCV(i, k)
                            If Not (oObj Is Nothing) Then
                                If oObj.ToString <> "" Then
                                    GoTo FoundCell
                                End If
                            End If
                            oObj = ExcelSheet.GetCV(k, i)
                            If Not (oObj Is Nothing) Then
                                If oObj.ToString <> "" Then
                                    GoTo FoundCellINV
                                End If
                            End If
                        Next
                    Next
FoundCellINV:
                    Dim l As Integer = i
                    i = k
                    k = l
FoundCell:
                    '// i has the row, k has the column
                    Do
                        ptOut.Name = ""
                        ptOut.North = 0
                        ptOut.East = 0
                        ptOut.Height = 0
                        ptOut.Descr = ""
                        bNorth = False
                        bEast = False
                        PtErrCnt = 0
                        Dim bErr As Boolean
                        For j = k To k + PT3PART.COUNT - 1
                            bErr = False
                            oObj = ExcelSheet.GetCV(i, j)

                            If oObj Is Nothing Then Continue For
                            Select Case lStgs.FOrd(j - k)
                                Case PT3PART.NAME
                                    ptOut.Name = oObj.ToString()
                                Case PT3PART.DESCR
                                    ptOut.Descr = oObj.ToString()
                                Case PT3PART.NORTH
                                    Try
                                        ptOut.North = CDbl(oObj)
                                        bNorth = True
                                    Catch ex As System.Exception
                                        bErr = True
                                    End Try
                                Case PT3PART.EAST
                                    Try
                                        ptOut.East = CDbl(oObj)
                                        bEast = True
                                    Catch ex As System.Exception
                                        bErr = True
                                    End Try
                                Case PT3PART.HEIGHT
                                    Try
                                        ptOut.Height = CDbl(oObj)
                                    Catch ex As System.Exception
                                        bErr = True
                                    End Try
                            End Select
                            If bErr = True Then
                                If (lStgs.bIgnErr) Then
                                    PtErrCnt = PtErrCnt + 1
                                    GoTo NextRow
                                End If
                                CMain.AlertUser( _
                                CMain._T(TX.PT3D_EIMP) & "!!!" & vbNewLine & vbNewLine & _
                                CMain._T(TX.LINE) & ": <" & _
                                i.ToString() & ">" & vbNewLine & _
                                CMain._T(TX.WORD) & ": <" & _
                                oObj.ToString() & ">")
                                Exit Try
                            End If
                        Next
                        If (bNorth = False Or bEast = False) Then
                            If (lStgs.bIgnErr) Then
                                PtErrCnt = PtErrCnt + 1
                                GoTo NextRow
                            End If
                            CMain.AlertUser( _
                            CMain._T(TX.PT3D_EIMP) & "!" & vbNewLine & _
                            CMain._T(TX.PT3D_ENE) & "!" & vbNewLine & vbNewLine & _
                            CMain._T(TX.LINE) & ": <" & _
                            i.ToString() & ">")
                            Exit Try
                        End If
                        '// now we have a dot
                        Dim BCrRet As Boolean
                        If (lStgs.doBlock) Then
                            BCrRet = BlockPoint(acDoc, ptOut, lStgs)
                        Else
                            BCrRet = EntityPoint(acDoc, ptOut, lStgs)
                        End If
                        If (BCrRet = False) Then
                            If (lStgs.bIgnErr) Then
                                PtErrCnt = PtErrCnt + 1
                                GoTo NextLine
                            End If
                            CMain.AlertUser( _
                            CMain._T(TX.PT3D_ECREATE) & "!" & vbNewLine & _
                            CMain._T(TX.LINE) & ": <" & _
                            i.ToString() & ">")
                            Exit Try
                        End If
                        PtCnt = PtCnt + 1
NextRow:
                        i = i + 1
                        oObj = ExcelSheet.GetCV(i, k)
                        If oObj Is Nothing Then Exit Do
                        If oObj.ToString() = "" Then Exit Do
                    Loop
                    sInputLine = Nothing
                End If
                Do Until sInputLine Is Nothing
                    ptOut.Name = ""
                    ptOut.North = 0
                    ptOut.East = 0
                    ptOut.Height = 0
                    ptOut.Descr = ""
                    bNorth = False
                    bEast = False
                    PartCnt = CMain.Ln2Tk(sInputLine, Parts, lStgs.FSep)
                    If (PartCnt >= 2) Then '// Nort and East are always required
                        For j = 0 To PartCnt - 1
                            If (j >= PT3PART.COUNT) Then Exit For
                            If (TokString( _
                                Parts(j), _
                                lStgs.FOrd(j), _
                                lStgs.DecSep, _
                                ptOut) = False) _
                            Then
                                If (lStgs.bIgnErr) Then
                                    PtErrCnt = PtErrCnt + 1
                                    GoTo NextLine
                                End If
                                CMain.AlertUser( _
                                CMain._T(TX.PT3D_EIMP) & "!!!" & vbNewLine & vbNewLine & _
                                CMain._T(TX.LINE) & ": <" & _
                                sInputLine & ">" & vbNewLine & _
                                CMain._T(TX.WORD) & ": <" & _
                                Parts(j) & ">")
                                Exit Try
                            End If
                            If (lStgs.FOrd(j) = PT3PART.NORTH) Then bNorth = True
                            If (lStgs.FOrd(j) = PT3PART.EAST) Then bEast = True
                        Next
                        If (bNorth = False Or bEast = False) Then
                            If (lStgs.bIgnErr) Then
                                PtErrCnt = PtErrCnt + 1
                                GoTo NextLine
                            End If
                            CMain.AlertUser( _
                            CMain._T(TX.PT3D_EIMP) & "!" & vbNewLine & _
                            CMain._T(TX.PT3D_ENE) & "!" & vbNewLine & vbNewLine & _
                            CMain._T(TX.LINE) & ": <" & _
                            sInputLine & ">")
                            Exit Try
                        End If

                        '// now we have a dot
                        Dim BCrRet As Boolean
                        If (kb IsNot Nothing) Then
                            BCrRet = kb(acDoc, ptOut, lStgs)
                        ElseIf (lStgs.doBlock) Then
                            BCrRet = BlockPoint(acDoc, ptOut, lStgs)
                        Else
                            BCrRet = EntityPoint(acDoc, ptOut, lStgs)
                        End If
                        If (BCrRet = False) Then
                            If (lStgs.bIgnErr) Then
                                PtErrCnt = PtErrCnt + 1
                                GoTo NextLine
                            End If
                            CMain.AlertUser( _
                            CMain._T(TX.PT3D_ECREATE) & "!" & vbNewLine & _
                            CMain._T(TX.LINE) & ": <" & _
                            sInputLine & ">")
                            Exit Try
                        End If
                        PtCnt = PtCnt + 1
                    End If
NextLine:
                    If (ExpTy = EXP_TXT) Then
                        sInputLine = srFileReader.ReadLine()
                    Else '//If (ExpTy = EXP_CLPB)
                        sInputLine = CMain.NextLine(sClipboard, iClIdx)
                    End If
                Loop
                If (lStgs.bIgnErr And PtErrCnt <> 0) Then
                    CMain.AlertUser( _
                            String.Format(CMain._T(TX.PT3D_IMPOK), PtCnt) & vbNewLine & _
                            String.Format(CMain._T(TX.PT3D_IMPFAIL), PtCnt) _
                    )
                Else
                    CMain.InformUser(String.Format(CMain._T(TX.PT3D_IMPOK), PtCnt))
                End If
                bRet = True
            Catch ex As System.Exception
                CMain.DebugException(ex)
            Finally
                If Not (srFileReader Is Nothing) Then
                    srFileReader.Close()
                ElseIf Not (ExcelWorkbook Is Nothing) Then
                    Call ExcelWorkbook.Close()
                    ExcelWorkbook = Nothing
                    ExcelSheet = Nothing
                End If
            End Try
            GC.Collect()
            GC.WaitForPendingFinalizers()
        End Using
        Return bRet

    End Function
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    '// The function that actually exports a file
    Public Function ExportFile(ByRef sFile As String, _
                                    ByRef lStgs As PT3DSTG) As Boolean
        Dim ExpTy As Integer


        Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
        If (acDoc Is Nothing) Then
            Return False
        End If

        ExpTy = EXP_TXT
        If (sFile.Length > 4) Then
            If ((sFile.Substring(sFile.Length - 4)).ToUpper() = ".XLS") Then
                ExpTy = EXP_XL
            ElseIf sFile = sCLIPB Then
                ExpTy = EXP_CLPB
            End If
        End If

        If (ExpTy <> EXP_XL) Then
            If (lStgs.DecSep.Length = 0) Then
                CMain.AlertUser(TX.PT3D_EDEC)
                Return False
            End If
            If (lStgs.FSep Is Nothing Or UBound(lStgs.FSep) = -1) Then
                CMain.AlertUser(TX.PT3D_EFLD)
                Return False
            End If
        End If

        Dim bRet As Boolean = False
        Dim db As Database = acDoc.Database
        Dim ed As Editor = acDoc.Editor

        '// Potential targets
        Dim objWRi As System.IO.StreamWriter = Nothing
        Dim ExcelSheet As XLS = Nothing
        Dim ExcelWorkbook As XLW = Nothing


        If (ExpTy = EXP_TXT) Then
            ' attempt to open a write stream
            Try
                objWRi = New System.IO.StreamWriter(sFile, False)
            Catch
            End Try
            If (objWRi Is Nothing) Then
                CMain.AlertUser(TX.EWRITE)
                Return False
            End If
        ElseIf (ExpTy = EXP_XL) Then
            If System.IO.File.Exists(sFile) Then
                ExcelWorkbook = New XLW(sFile)
            Else
                ExcelWorkbook = New XLW()
                If (ExcelWorkbook.ErrSts <> XLW.ERR.OK) Then
                    CMain.AlertUser(TX.EWRITE)
                    Return False
                End If
                ExcelWorkbook.SaveAs(sFile)
            End If
            If (ExcelWorkbook Is Nothing) Then
                CMain.AlertUser(TX.EWRITE)
                Return False
            End If
            ExcelSheet = ExcelWorkbook.GetActiveSheet()
        End If

        Using acTrans As Transaction = _
            db.TransactionManager.StartTransaction()
            Try
                '// get a reference to table of blocks
                Dim acBlkTbl As BlockTable = DirectCast( _
                 acTrans.GetObject(db.BlockTableId, OpenMode.ForRead),  _
                 BlockTable)

                '// Get Model space (is just a block)
                Dim acBlkModel As BlockTableRecord = DirectCast( _
                    acTrans.GetObject( _
                        acBlkTbl(BlockTableRecord.ModelSpace), _
                        OpenMode.ForWrite),  _
                    BlockTableRecord)

                '// see if our block is inside
                If (acBlkTbl.Has(lStgs.sBlockName) = False) Then
                    CMain.AlertUser(String.Format(CMain._T(TX.PT3D_EBLK), lStgs.sBlockName))
                    Exit Try
                End If
                Dim oidTargBlk As ObjectId = acBlkTbl(lStgs.sBlockName)
                Dim iT As Integer = 0

                '' Get the PickFirst selection set
                Dim acSSPrompt As PromptSelectionResult = ed.SelectImplied()
                '' If the prompt status is OK, objects were selected before
                '' the command was started
                If acSSPrompt.Status = PromptStatus.OK Then
                    Dim acSSet As SelectionSet = acSSPrompt.Value
                    If (ExpTy = EXP_TXT) Then
                        For Each sobj As SelectedObject In acSSet
                            If Export_txt_Unit(acTrans, objWRi, lStgs.FSep(0), oidTargBlk, sobj.ObjectId, lStgs) = True Then
                                iT = iT + 1
                            End If
                        Next
                    ElseIf (ExpTy = EXP_XL) Then
                        Dim i As Integer = 1
                        For Each sobj As SelectedObject In acSSet
                            If Export_EX_Unit(acTrans, ExcelSheet, i, oidTargBlk, sobj.ObjectId) = True Then
                                iT = iT + 1
                            End If
                        Next
                    Else '// Clipboard
                        Dim SOut As String = ""
                        For Each sobj As SelectedObject In acSSet
                            If Export_Clp_Unit(acTrans, SOut, lStgs.FSep(0), oidTargBlk, sobj.ObjectId, lStgs) = True Then
                                iT = iT + 1
                            End If
                        Next
                        Windows.Forms.Clipboard.SetText(SOut)
                    End If

                    If iT = 0 Then
                        CMain.InformUser(TX.PT3D_NPT)
                        GoTo DoAllBlocks
                    End If
                Else
DoAllBlocks:
                    ' holds the id for curently iterated object
                    ' loop in all entities from model space
                    If (ExpTy = EXP_TXT) Then
                        For Each idBlkd As ObjectId In acBlkModel
                            If Export_txt_Unit(acTrans, objWRi, lStgs.FSep(0), oidTargBlk, idBlkd, lStgs) = True Then
                                iT = iT + 1
                            End If
                        Next idBlkd
                    ElseIf (ExpTy = EXP_XL) Then
                        Dim i As Integer = 1
                        For Each idBlkd As ObjectId In acBlkModel
                            If Export_EX_Unit(acTrans, ExcelSheet, i, oidTargBlk, idBlkd) = True Then
                                iT = iT + 1
                            End If
                        Next idBlkd
                    Else '// Clipboard
                        Dim SOut As String = ""
                        For Each idBlkd As ObjectId In acBlkModel
                            If Export_Clp_Unit(acTrans, SOut, lStgs.FSep(0), oidTargBlk, idBlkd, lStgs) = True Then
                                iT = iT + 1
                            End If
                        Next idBlkd
                        Windows.Forms.Clipboard.SetText(SOut)
                    End If
                End If
                If Not (ExcelWorkbook Is Nothing) Then
                    Call ExcelWorkbook.Close(True)
                    ExcelWorkbook = Nothing
                End If

                CMain.InformUser(String.Format(CMain._T(TX.PT3D_EXPOK), iT))

                acTrans.Commit()
                bRet = True
                Exit Try
BadFile:

            Catch ex As System.Exception
                acTrans.Abort()
                CMain.DebugException(ex)
            Finally
                If (Not objWRi Is Nothing) Then
                    objWRi.Close()
                ElseIf Not (ExcelWorkbook Is Nothing) Then
                    Call ExcelWorkbook.Close(False)
                    ExcelWorkbook = Nothing
                    ExcelSheet = Nothing
                End If

            End Try
            GC.Collect()
            GC.WaitForPendingFinalizers()
        End Using

        Return bRet
    End Function
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    '// Matches the coordinates with points in file
    Public Shared Sub MatchPoints(ByRef acDoc As Document, ByRef pts() As FSK_PT3D)

        Using acTrans As Transaction = _
            acDoc.Database.TransactionManager.StartTransaction()
            Try
                '// get a reference to table of blocks
                Dim acBlkTbl As BlockTable = DirectCast( _
                 acTrans.GetObject(acDoc.Database.BlockTableId, OpenMode.ForRead),  _
                 BlockTable)

                '// Get Model space (is just a block)
                Dim acBlkModel As BlockTableRecord = DirectCast( _
                    acTrans.GetObject( _
                        acBlkTbl(BlockTableRecord.ModelSpace), _
                        OpenMode.ForWrite),  _
                    BlockTableRecord)

                '// see if our block is inside
                If (acBlkTbl.Has(Stgs.sBlockName) = False) Then
                    CMain.AlertUser(String.Format(CMain._T( _
                                        TX.PT3D_EBLK), Stgs.sBlockName))
                    Exit Try
                End If
                Dim oIdTarg As ObjectId = acBlkTbl(Stgs.sBlockName)
                Dim iT As Integer = 0

                For Each idBlkd As ObjectId In acBlkModel
                    Dim Ent As DBObject = acTrans.GetObject(idBlkd, OpenMode.ForRead)
                    If TypeOf Ent Is BlockReference Then
                        ' "cast" the entity into a block reference
                        Dim blkRef As BlockReference = DirectCast(Ent, BlockReference)
                        '' see if this is our kind of block
                        If blkRef.BlockTableRecord <> oIdTarg Then Continue For
                        If blkRef.AttributeCollection.Count = 0 Then Continue For
                        ' prepare the properties  list
                        Dim sName As String
                        Dim sCode As String
                        ' loop in dynamic properties
                        sName = ""
                        sCode = ""
                        For Each acAtId As ObjectId In blkRef.AttributeCollection
                            Dim acAtrRef As AttributeReference = _
                             DirectCast(acTrans.GetObject(acAtId, OpenMode.ForRead),  _
                             AttributeReference)
                            Select Case acAtrRef.Tag.ToUpper
                                Case sPTOA_NAME
                                    sName = acAtrRef.TextString
                                    'Case sPTOA_Z
                                Case sPTOA_CODE
                                    sCode = acAtrRef.TextString
                            End Select
                        Next
                        '// we have a point; see if is in our list
                        Dim jj As Integer = 0
                        For Each pt In pts 'the text is rounded, so can't use CMain method
                            If (Math.Abs(pt.North - blkRef.Position.Y) < 0.001) Then
                                If (Math.Abs(pt.East - blkRef.Position.X) < 0.001) Then
                                    pts(jj).Height = blkRef.Position.Z
                                    pts(jj).Descr = sCode
                                    pts(jj).Name = sName
                                    Exit For
                                End If
                            End If
                            jj = jj + 1
                        Next

                    End If
                Next idBlkd

            Catch ex As System.Exception
                acTrans.Abort()
                CMain.DebugException(ex)
            End Try
            GC.Collect()
            GC.WaitForPendingFinalizers()
        End Using
    End Sub
    '// ===================================================================== '


#End Region


#Region "C O M M A N D S"


    '// --------------------------------------------------------------------- '
    '// display settings dialog
    <CommandMethod(sCMD_SETTINGS)> _
    Public Sub Show_Settings()
        Try
            Dim StgD As CST_3DPoints = New CST_3DPoints
            Application.ShowModalDialog(StgD)

        Catch ex As System.Exception
            CMain.PopUpExc()
            CMain.DebugException(ex)
        End Try
        GC.Collect()
        GC.WaitForPendingFinalizers()
    End Sub
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    '// display import dialog
    <CommandMethod(sCMD_IMPORT)> _
    Public Sub Import()
        Try
            Dim D As CD_ImpEx = New CD_ImpEx(Me, True)
            Application.ShowModalDialog(D)
        Catch ex As System.Exception
            CMain.PopUpExc()
            CMain.DebugException(ex)
        End Try
        GC.Collect()
        GC.WaitForPendingFinalizers()
    End Sub
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    '// display export dialog
    <CommandMethod(sCMD_EXPORT, CommandFlags.UsePickSet)> _
    Public Sub Export()
        Try
            Dim D As CD_ImpEx = New CD_ImpEx(Me, False)
            If (Application.ShowModalDialog(D) = Windows.Forms.DialogResult.OK) Then
                SaveSett()
            End If
        Catch ex As System.Exception
            CMain.PopUpExc()
            CMain.DebugException(ex)
        End Try
        GC.Collect()
        GC.WaitForPendingFinalizers()
    End Sub
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    '// create coresponding entities
    <CommandMethod(sCMD_EXPLODE, CommandFlags.UsePickSet)> _
    Public Sub Explode()
        Try
            Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
            If (acDoc Is Nothing) Then
                Return
            End If

            Dim db As Database = acDoc.Database
            Dim ed As Editor = acDoc.Editor
            ed = acDoc.Editor

            Using acTrans As Transaction = _
                db.TransactionManager.StartTransaction()
                Try
                    '// get a reference to table of blocks
                    Dim acBlkTbl As BlockTable = DirectCast( _
                     acTrans.GetObject(db.BlockTableId, OpenMode.ForRead),  _
                     BlockTable)

                    '// Get Model space (is just a block)
                    Dim acBlkModel As BlockTableRecord = DirectCast( _
                        acTrans.GetObject( _
                            acBlkTbl(BlockTableRecord.ModelSpace), _
                            OpenMode.ForWrite),  _
                        BlockTableRecord)

                    '// see if our block is inside
                    If (acBlkTbl.Has(CM_3DPoints.Stgs.sBlockName) = False) Then
                        CMain.AlertUser(String.Format(CMain._T(TX.PT3D_EBLK), CM_3DPoints.Stgs.sBlockName))
                        Exit Try
                    End If
                    Dim oidTargBlk As ObjectId = acBlkTbl(CM_3DPoints.Stgs.sBlockName)
                    Dim iT As Integer = 0

                    '' Get the PickFirst selection set
                    Dim acSSPrompt As PromptSelectionResult = ed.SelectImplied()
                    '' If the prompt status is OK, objects were selected before
                    '' the command was started
                    If acSSPrompt.Status = PromptStatus.OK Then
                        Dim acSSet As SelectionSet = acSSPrompt.Value
                        For Each sobj As SelectedObject In acSSet
                            If (Explode_Entity(acDoc, acTrans, acBlkModel, oidTargBlk, sobj.ObjectId)) Then
                                iT = iT + 1
                            End If
                        Next
                        If iT = 0 Then
                            CMain.InformUser(TX.PT3D_NPT)
                            GoTo DoAllBlocks
                        End If
                    Else
DoAllBlocks:
                        For Each idBlkd As ObjectId In acBlkModel
                            If (Explode_Entity(acDoc, acTrans, acBlkModel, oidTargBlk, idBlkd)) Then
                                iT = iT + 1
                            End If
                        Next
                    End If

                    CMain.InformUser(String.Format(CMain._T(TX.PT3D_EXPLDOK), iT))
                    acTrans.Commit()
                    Exit Try
                Catch ex As System.Exception
                    acTrans.Abort()
                    CMain.DebugException(ex)
                End Try
            End Using

        Catch ex As System.Exception
            CMain.PopUpExc()
            CMain.DebugException(ex)
        End Try
        GC.Collect()
        GC.WaitForPendingFinalizers()
    End Sub
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    '// Change properties of some / all blocks
    <CommandMethod(sCMD_EDIT, CommandFlags.UsePickSet)> _
    Public Sub Edit()
        Try
            Dim D As New CED_3DPoints()
            Application.ShowModelessDialog(D)
        Catch ex As System.Exception
            CMain.PopUpExc()
            CMain.DebugException(ex)
        End Try
        GC.Collect()
        GC.WaitForPendingFinalizers()
    End Sub
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    '// Get the coordinates of a polyline
    <CommandMethod(sCMD_POLYPT, CommandFlags.UsePickSet)> _
    Public Sub GetPolyPts()
        Try
            Dim D As New CD_PolyPt()
            Application.ShowModelessDialog(D)

        Catch ex As System.Exception
            CMain.PopUpExc()
            CMain.DebugException(ex)
        End Try
        GC.Collect()
        GC.WaitForPendingFinalizers()
    End Sub
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    '// Get the distance between two points
    <CommandMethod(sCMD_DIST)> _
    Public Sub GetPtsDist()
        Try
            Dim dAlfaRad As Double
            Dim sTxOut As String
            
            Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
            If (acDoc Is Nothing) Then
                Return
            End If
            Dim Ln_bVert as Boolean = True
            Dim Ln_m As Double
            Dim Ln_b As Double

            Dim db As Database = acDoc.Database
            Dim ed As Editor = acDoc.Editor
            ed = acDoc.Editor

            Using acTrans As Transaction = _
                db.TransactionManager.StartTransaction()
                Try

			        Dim ppo As PromptPointOptions
			        Dim ppr1 As PromptPointResult
			        Dim ppr2 As PromptPointResult
                    Dim bVert As Boolean = False
                    Dim dDst2D As Double
                    Dim dDst3D As Double

			        ppo = New PromptPointOptions(vbLf & CMain._T(TX.FPOINT) & ":")
			        ppr1 = ed.GetPoint(ppo)
                    ppo.Keywords.Clear()
			        If ppr1.Status <> PromptStatus.OK Then
                        Exit Try
                    End If

                    ppo.BasePoint = ppr1.Value
                    ppo.UseBasePoint = True
                    ppo.Message = vbLf & CMain._T(TX.SPOINT) & ":"
                    Do
			            ppr2 = ed.GetPoint(ppo)
			            If ppr2.Status <> PromptStatus.OK Then Exit Try
                        If Math.Abs(ppr2.Value.Y - ppr1.Value.Y) > CMain.MARGIN Then Exit Do
                        If Math.Abs(ppr2.Value.X - ppr1.Value.X) > CMain.MARGIN Then Exit Do
                        CMain.AlertUser(TX.ERR_PTCLOSE)
                    Loop

                    dDst2D = (ppr2.Value.X - ppr1.Value.X)
                    If (Math.Abs(dDst2D) < CMain.MARGIN) Then
                        Ln_bVert = True
                        Ln_m = 0
                        Ln_b = 0
                        dAlfaRad = Math.PI / 2
                    Else
                        Ln_bVert = False
                        Ln_m = ((ppr2.Value.Y - ppr1.Value.Y) / dDst2D)
                        Ln_b = ppr1.Value.Y - Ln_m * ppr1.Value.X
                        dAlfaRad = Math.Atan(Ln_m)
                    End If

                    dDst2D = Math.Sqrt( _
                            Math.Pow((ppr2.Value.X - ppr1.Value.X), 2) + _
                            Math.Pow((ppr2.Value.Y - ppr1.Value.Y), 2))
                    dDst3D = Math.Sqrt( _
                            Math.Pow((ppr2.Value.Z - ppr1.Value.Z), 2) + _
                            Math.Pow((ppr2.Value.X - ppr1.Value.X), 2) + _
                            Math.Pow((ppr2.Value.Y - ppr1.Value.Y), 2))
                    sTxOut = vbNewLine & "===================================================" & vbNewLine
                    If (Ln_bVert = True) Then
                        sTxOut = sTxOut & _
                             "Tan" & " = " & "vertical" & vbNewLine
                    Else
                        sTxOut = sTxOut & _
                             "Tan" & " = " & Ln_m.ToString("0.000000") & vbNewLine
                    End If

                    sTxOut = sTxOut & _
                             CMain._T(TX.ANG_P_RAD) & " = " & dAlfaRad.ToString("0.0000") & vbNewLine & _
                             CMain._T(TX.ANG_P_360) & " = " & (dAlfaRad*180/Math.PI).ToString("0.0000") & vbNewLine & _
                             CMain._T(TX.ANG_P_400) & " = " & (dAlfaRad*200/Math.PI).ToString("0.0000") & vbNewLine & _
                             CMain._T(TX.DELTA_EAST) & " = " & (ppr2.Value.X - ppr1.Value.X).ToString("0.000") & vbNewLine & _
                             CMain._T(TX.DELTA_NORTH) & " = " & (ppr2.Value.Y - ppr1.Value.Y).ToString("0.000") & vbNewLine & _
                             CMain._T(TX.DELTA_ELEV) & " = " & (ppr2.Value.Z - ppr1.Value.Z).ToString("0.000") & vbNewLine & _
                             CMain._T(TX. DIST_2D) & " = " & dDst2D.ToString("0.000") & vbNewLine & _
                             CMain._T(TX.DIST_3D) & " = " & dDst3D.ToString("0.000") & vbNewLine & _
                             "===================================================" & vbNewLine
                    CMain.InformUser(sTxOut)


                    acTrans.Commit()
                Catch ex As System.Exception
                    acTrans.Abort()
                    CMain.DebugException(ex)
                End Try
            End Using

        Catch ex As System.Exception
            CMain.PopUpExc()
            CMain.DebugException(ex)
        End Try
        GC.Collect()
        GC.WaitForPendingFinalizers()
    End Sub
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    '// Place a number of points between two points
    <CommandMethod(sCMD_INTERM)> _
    Public Sub PlacePtsBetween()
        Try

            Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
            If (acDoc Is Nothing) Then
                Return
            End If

            Dim db As Database = acDoc.Database
            Dim ed As Editor = acDoc.Editor
            ed = acDoc.Editor

            Using acTrans As Transaction = _
                db.TransactionManager.StartTransaction()
                Try

                    Dim dAlfaRad As Double
			        Dim ppo As PromptPointOptions
			        Dim ppr1 As PromptPointResult
			        Dim ppr2 As PromptPointResult
                    Dim bVert As Boolean = False
                    Dim dDst2D As Double
                    Dim Ln_bVert as Boolean = True
                    Dim Ln_m As Double
                    Dim Ln_b As Double

			        ppo = New PromptPointOptions(vbLf & CMain._T(TX.FPOINT) & ":")
			        ppr1 = ed.GetPoint(ppo)
                    ppo.Keywords.Clear()
			        If ppr1.Status <> PromptStatus.OK Then
                        Exit Try
                    End If

                    ppo.BasePoint = ppr1.Value
                    ppo.UseBasePoint = True
                    ppo.Message = vbLf & CMain._T(TX.SPOINT) & ":"
                    Do
			            ppr2 = ed.GetPoint(ppo)
			            If ppr2.Status <> PromptStatus.OK Then Exit Try
                        If Math.Abs(ppr2.Value.Y - ppr1.Value.Y) > CMain.MARGIN Then Exit Do
                        If Math.Abs(ppr2.Value.X - ppr1.Value.X) > CMain.MARGIN Then Exit Do
                        CMain.AlertUser(TX.ERR_PTCLOSE)
                    Loop

                    dDst2D = (ppr2.Value.X - ppr1.Value.X)
                    If (Math.Abs(dDst2D) < CMain.MARGIN) Then
                        Ln_bVert = True
                        Ln_m = 0
                        Ln_b = 0
                        dAlfaRad = Math.PI / 2
                    Else
                        Ln_bVert = False
                        Ln_m = ((ppr2.Value.Y - ppr1.Value.Y) / dDst2D)
                        Ln_b = ppr1.Value.Y - Ln_m * ppr1.Value.X
                        dAlfaRad = Math.Atan(Ln_m)
                    End If

                    Dim pdr As Autodesk.AutoCAD.EditorInput.PromptDoubleResult
                    Dim pdo As Autodesk.AutoCAD.EditorInput.PromptDoubleOptions
        
                    pdo = New PromptDoubleOptions((vbLf & CMain._T(TX.PARTS) & ":"))
                    pdo.AppendKeywordsToMessage = True
                    pdo.AllowNegative = False
                    pdo.AllowZero = False
                    'If (Stgs.dLastInA > 0) Then
                    '    pdo.DefaultValue = Stgs.dLastInA
                    'End If
                    pdr = ed.GetDouble(pdo)
                    If pdr.Status <> PromptStatus.OK Then Exit Try

                    dDst2D = Math.Sqrt( _
                            Math.Pow((ppr2.Value.X - ppr1.Value.X), 2) + _
                            Math.Pow((ppr2.Value.Y - ppr1.Value.Y), 2))

                    Dim pt As FSK_PT3D = Nothing
                    Dim dDstSp = dDst2D / pdr.Value
                    Dim dDstCum As Double = dDstSp
                    Dim dZ As Double = (ppr2.Value.Z - ppr1.Value.Z)
                    Dim iNumber As Integer = 100
                    Try
                        iNumber = CInt(Stgs.sNameSave)
                    Catch
                    End Try
                    For i As Integer = 1 to pdr.Value-1
                        pt.Name = iNumber.ToString
                        pt.Descr = "+"
                        pt.North = ppr1.Value.Y + dDstCum * Math.Sin(dAlfaRad)
                        pt.East = ppr1.Value.X + dDstCum * Math.Cos(dAlfaRad)
                        pt.Height = ppr1.Value.Z + (dDstCum / dDst2D)*dZ
                        If Stgs.doBlock Then
                            BlockPoint(acDoc,pt,Stgs)
                        Else
                            EntityPoint(acDoc,pt,Stgs)
                        End if
                        dDstCum = dDstCum + dDstSp
                        iNumber = iNumber + 1
                    Next
                    Stgs.sNameSave = iNumber.ToString

                    acTrans.Commit()
                Catch ex As System.Exception
                    acTrans.Abort()
                    CMain.DebugException(ex)
                End Try
            End Using

        Catch ex As System.Exception
            CMain.PopUpExc()
            CMain.DebugException(ex)
        End Try
        GC.Collect()
        GC.WaitForPendingFinalizers()
    End Sub
    '// ===================================================================== '

#End Region






End Class
'//  CLASS    =============================================================== '
'//
'//
'//
'//
'//  FUNCTIONS    ----------------------------------------------------------- '

'//  FUNCTIONS    =========================================================== '
'//
'//
'//
'//
'// ------------------------------------------------------------------------- '
'// ========================================================================= '





